@triflux/core 10.50.2 → 10.52.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/agy-session-hook.mjs +11 -56
- package/hooks/codex-session-hook.mjs +11 -101
- package/hub/bridge.mjs +65 -1250
- package/hub/cli-adapter-base.mjs +12 -90
- package/hub/codex-adapter.mjs +0 -1
- package/hub/codex-preflight.mjs +5 -28
- package/hub/index.mjs +3 -19
- package/hub/lib/process-utils.mjs +1 -156
- package/hub/lib/spawn-trace.mjs +3 -2
- package/hub/lib/timeout-defaults.mjs +0 -1
- package/hub/team/claude-daemon-control.mjs +1 -2
- package/hub/team/claude-session-projection.mjs +5 -73
- package/hub/team/nativeProxy.mjs +759 -0
- package/hub/team/session-context.mjs +1 -1
- package/hud/cli-policy.mjs +0 -22
- package/hud/constants.mjs +13 -26
- package/hud/hud-qos-status.mjs +42 -54
- package/hud/providers/gemini.mjs +125 -20
- package/hud/renderers.mjs +101 -122
- package/hud/utils.mjs +10 -6
- package/package.json +2 -6
- package/scripts/lib/agent-route-policy.mjs +143 -62
- package/scripts/lib/cli-claude.mjs +0 -14
- package/scripts/lib/env-probe.mjs +2 -131
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-guard-engine.mjs +40 -98
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +11 -59
- package/scripts/lib/session-presence.mjs +2 -100
- package/scripts/lib/skill-template.mjs +0 -245
- package/hub/adaptive-diagnostic.mjs +0 -350
- package/hub/adaptive-inject.mjs +0 -224
- package/hub/adaptive-memory.mjs +0 -277
- package/hub/adaptive.mjs +0 -172
- package/hub/assign-callbacks.mjs +0 -170
- package/hub/delegator/contracts.mjs +0 -38
- package/hub/delegator/index.mjs +0 -14
- package/hub/delegator/schema/delegator-tools.schema.json +0 -250
- package/hub/delegator/service.mjs +0 -336
- package/hub/delegator/tool-definitions.mjs +0 -35
- package/hub/dynamic-routing-engine.mjs +0 -511
- package/hub/hitl.mjs +0 -202
- package/hub/lib/known-errors.json +0 -72
- package/hub/lib/memory-store.mjs +0 -1001
- package/hub/lib/phase-manager.mjs +0 -493
- package/hub/lib/risk-tier.mjs +0 -53
- package/hub/lib/ssh-command.mjs +0 -231
- package/hub/lib/staged-file-detect.mjs +0 -43
- package/hub/lib/state-snapshot.mjs +0 -293
- package/hub/lib/tfx-route-args.mjs +0 -353
- package/hub/lib/trace-recorder.mjs +0 -153
- package/hub/lib/uuidv7.mjs +0 -45
- package/hub/memory-doctor.mjs +0 -640
- package/hub/middleware/quota-middleware.mjs +0 -70
- package/hub/middleware/request-logger.mjs +0 -191
- package/hub/paths.mjs +0 -24
- package/hub/pipeline/index.mjs +0 -163
- package/hub/pipeline/state.mjs +0 -191
- package/hub/pipeline/transitions.mjs +0 -131
- package/hub/reflexion.mjs +0 -290
- package/hub/role-contract.mjs +0 -314
- package/hub/router.mjs +0 -2026
- package/hub/routing-snapshot.mjs +0 -261
- package/hub/session-fingerprint.mjs +0 -418
- package/hub/state.mjs +0 -300
- package/hub/team/synapse-http.mjs +0 -311
- package/hub/team-bridge.mjs +0 -27
- package/mesh/index.mjs +0 -69
- package/mesh/mesh-budget.mjs +0 -137
- package/mesh/mesh-heartbeat.mjs +0 -100
- package/mesh/mesh-protocol.mjs +0 -96
- package/mesh/mesh-queue.mjs +0 -163
- package/mesh/mesh-registry.mjs +0 -78
- package/mesh/mesh-router.mjs +0 -77
- package/scripts/lib/claudemd-scanner.mjs +0 -223
- package/scripts/lib/context.mjs +0 -67
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
- package/scripts/lib/handoff.mjs +0 -187
- package/scripts/lib/logger.mjs +0 -122
- package/scripts/lib/stealth-fetch.mjs +0 -176
package/hud/renderers.mjs
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// 라인 렌더러 (tier별 행 생성)
|
|
3
3
|
// ============================================================================
|
|
4
|
-
import { readdirSync, statSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
6
4
|
import {
|
|
7
5
|
bold,
|
|
8
6
|
CLAUDE_ORANGE,
|
|
@@ -12,17 +10,19 @@ import {
|
|
|
12
10
|
colorByPercent,
|
|
13
11
|
colorByProvider,
|
|
14
12
|
dim,
|
|
13
|
+
GAUGE_WIDTH,
|
|
14
|
+
GEMINI_BLUE,
|
|
15
15
|
geminiBlue,
|
|
16
|
-
green,
|
|
17
|
-
red,
|
|
18
16
|
yellow,
|
|
19
17
|
} from "./colors.mjs";
|
|
20
18
|
import {
|
|
21
19
|
ACCOUNT_LABEL_WIDTH,
|
|
22
20
|
FIVE_HOUR_MS,
|
|
21
|
+
ONE_DAY_MS,
|
|
22
|
+
PERCENT_CELL_WIDTH,
|
|
23
23
|
PROVIDER_PREFIX_WIDTH,
|
|
24
24
|
SEVEN_DAY_MS,
|
|
25
|
-
|
|
25
|
+
TIME_CELL_INNER_WIDTH,
|
|
26
26
|
} from "./constants.mjs";
|
|
27
27
|
import { buildContextUsageView } from "./context-monitor.mjs";
|
|
28
28
|
import { getTerminalColumns, tierBar, tierDimBar } from "./terminal.mjs";
|
|
@@ -36,94 +36,10 @@ import {
|
|
|
36
36
|
formatTimeCell,
|
|
37
37
|
formatTimeCellDH,
|
|
38
38
|
padAnsiRight,
|
|
39
|
-
readJson,
|
|
40
39
|
stripAnsi,
|
|
41
40
|
truncateAnsi,
|
|
42
41
|
} from "./utils.mjs";
|
|
43
42
|
|
|
44
|
-
// ============================================================================
|
|
45
|
-
// tfx-multi 상태 행 생성 (v2.2 HUD 통합)
|
|
46
|
-
// ============================================================================
|
|
47
|
-
export function getTeamRow(currentTier, stateDir = TEAM_STATE_DIR) {
|
|
48
|
-
let latestPath = null;
|
|
49
|
-
let latestMtime = Date.now() - 24 * 60 * 60 * 1000;
|
|
50
|
-
try {
|
|
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
|
-
}
|
|
64
|
-
} catch {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
const teamState = latestPath ? readJson(latestPath, null) : null;
|
|
68
|
-
if (!teamState?.sessionName) return null;
|
|
69
|
-
|
|
70
|
-
const workers = (teamState.members || []).filter((m) => m.role === "worker");
|
|
71
|
-
if (!workers.length) return null;
|
|
72
|
-
|
|
73
|
-
const tasks = teamState.tasks || [];
|
|
74
|
-
const completed = tasks.filter((t) => t.status === "completed").length;
|
|
75
|
-
const failed = tasks.filter((t) => t.status === "failed").length;
|
|
76
|
-
const total = tasks.length || workers.length;
|
|
77
|
-
|
|
78
|
-
// 경과 시간 (80col 이상에서만 표시)
|
|
79
|
-
const elapsed =
|
|
80
|
-
teamState.startedAt && (currentTier === "full" || currentTier === "compact")
|
|
81
|
-
? `${Math.round((Date.now() - teamState.startedAt) / 60000)}m`
|
|
82
|
-
: "";
|
|
83
|
-
|
|
84
|
-
// CLI 브랜드: 단일문자 + ANSI 색상 (x=codex, g=gemini, c=claude)
|
|
85
|
-
const cliTag = (cli) =>
|
|
86
|
-
cli === "codex"
|
|
87
|
-
? bold(codexWhite("x"))
|
|
88
|
-
: cli === "gemini"
|
|
89
|
-
? bold(geminiBlue("g"))
|
|
90
|
-
: bold(claudeOrange("c"));
|
|
91
|
-
// 멤버 상태: 태그 + 상태기호 (60col 이상)
|
|
92
|
-
const memberIcons =
|
|
93
|
-
currentTier === "full" ||
|
|
94
|
-
currentTier === "compact" ||
|
|
95
|
-
currentTier === "minimal"
|
|
96
|
-
? workers
|
|
97
|
-
.map((m) => {
|
|
98
|
-
const task = tasks.find((t) => t.owner === m.name);
|
|
99
|
-
const status =
|
|
100
|
-
task?.status === "completed"
|
|
101
|
-
? green("\u2713")
|
|
102
|
-
: task?.status === "in_progress"
|
|
103
|
-
? yellow("\u22EF")
|
|
104
|
-
: task?.status === "failed"
|
|
105
|
-
? red("\u2717")
|
|
106
|
-
: dim("\u25CC");
|
|
107
|
-
return `${cliTag(m.cli)}${status}`;
|
|
108
|
-
})
|
|
109
|
-
.join(" ")
|
|
110
|
-
: "";
|
|
111
|
-
|
|
112
|
-
// 진행 텍스트
|
|
113
|
-
const doneText =
|
|
114
|
-
failed > 0
|
|
115
|
-
? `${completed}/${total} ${red(`${failed}\u2717`)}`
|
|
116
|
-
: `${completed}/${total}`;
|
|
117
|
-
|
|
118
|
-
const leftText = elapsed ? `${doneText} ${dim(elapsed)}` : doneText;
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
prefix: bold(claudeOrange("\u25B2")),
|
|
122
|
-
left: leftText,
|
|
123
|
-
right: memberIcons,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
43
|
// ============================================================================
|
|
128
44
|
// 행 정렬 렌더링
|
|
129
45
|
// ============================================================================
|
|
@@ -142,9 +58,7 @@ export function renderAlignedRows(rows) {
|
|
|
142
58
|
if (!hasRight) {
|
|
143
59
|
return truncateAnsi(`${prefix} ${row.left}`, cols);
|
|
144
60
|
}
|
|
145
|
-
|
|
146
|
-
const ownLen = stripAnsi(row.left).length;
|
|
147
|
-
const effectiveWidth = Math.min(rawLeftWidth, ownLen + 2);
|
|
61
|
+
const effectiveWidth = rawLeftWidth;
|
|
148
62
|
const left = padAnsiRight(row.left, effectiveWidth);
|
|
149
63
|
// 우선순위 기반 truncate: right 먼저 축소, 그래도 넘치면 left 축소
|
|
150
64
|
// prefix(PROVIDER_PREFIX_WIDTH) + " "(1) + left(effectiveWidth) + " | "(3) + right
|
|
@@ -169,10 +83,9 @@ export function getMicroLine(
|
|
|
169
83
|
contextView,
|
|
170
84
|
claudeUsage,
|
|
171
85
|
codexBuckets,
|
|
172
|
-
antigravityReady,
|
|
173
86
|
options = {},
|
|
174
87
|
) {
|
|
175
|
-
const { showCodex = true,
|
|
88
|
+
const { showCodex = true, showAntigravity = true } = options;
|
|
176
89
|
const ctxView = contextView || buildContextUsageView({});
|
|
177
90
|
// Claude 5h/1w
|
|
178
91
|
const cF =
|
|
@@ -211,19 +124,35 @@ export function getMicroLine(
|
|
|
211
124
|
if (showCodex) {
|
|
212
125
|
segments.push(`${bold(codexWhite("x"))}${dim(":")}${xVal}`);
|
|
213
126
|
}
|
|
214
|
-
if (
|
|
127
|
+
if (showAntigravity) {
|
|
128
|
+
const marker = options.antigravityQuota?.auth
|
|
129
|
+
? bold(geminiBlue("a"))
|
|
130
|
+
: dim("a");
|
|
215
131
|
segments.push(
|
|
216
|
-
`${
|
|
132
|
+
`${marker}${dim(":")}${antigravityPercentText(options.antigravityQuota)}${options.antigravityQuota?.stale ? dim("*") : ""}`,
|
|
217
133
|
);
|
|
218
134
|
}
|
|
219
135
|
segments.push(`${dim("CTX:")}${contextPercentText(ctxView)}`);
|
|
220
136
|
return truncateAnsi(segments.join(" "), cols);
|
|
221
137
|
}
|
|
222
138
|
|
|
139
|
+
function antigravityPercentText(quota) {
|
|
140
|
+
if (quota?.auth === "project") {
|
|
141
|
+
return geminiBlue("GCP".padStart(PERCENT_CELL_WIDTH));
|
|
142
|
+
}
|
|
143
|
+
return quota?.usedPercent != null
|
|
144
|
+
? colorByProvider(
|
|
145
|
+
quota.usedPercent,
|
|
146
|
+
formatPercentCell(quota.usedPercent),
|
|
147
|
+
geminiBlue,
|
|
148
|
+
)
|
|
149
|
+
: dim(formatPlaceholderPercentCell());
|
|
150
|
+
}
|
|
151
|
+
|
|
223
152
|
// context 는 토큰 수 대신 사용률만 보여 준다.
|
|
224
153
|
function contextPercentText(ctxView) {
|
|
225
|
-
|
|
226
|
-
return colorByPercent(ctxView.percent,
|
|
154
|
+
if (ctxView.display === "--") return dim("--%");
|
|
155
|
+
return colorByPercent(ctxView.percent, `${ctxView.percent}%`);
|
|
227
156
|
}
|
|
228
157
|
|
|
229
158
|
// ============================================================================
|
|
@@ -237,10 +166,10 @@ export function getClaudeRows(currentTier, contextView, claudeUsage) {
|
|
|
237
166
|
const weeklyPercent = claudeUsage?.weeklyPercent ?? null;
|
|
238
167
|
const fiveHourReset = claudeUsage?.fiveHourResetsAt
|
|
239
168
|
? formatResetRemaining(claudeUsage.fiveHourResetsAt, FIVE_HOUR_MS)
|
|
240
|
-
: "
|
|
169
|
+
: "";
|
|
241
170
|
const weeklyReset = claudeUsage?.weeklyResetsAt
|
|
242
171
|
? formatResetRemainingDayHour(claudeUsage.weeklyResetsAt, SEVEN_DAY_MS)
|
|
243
|
-
: "
|
|
172
|
+
: "";
|
|
244
173
|
|
|
245
174
|
const hasData = claudeUsage != null;
|
|
246
175
|
|
|
@@ -275,11 +204,11 @@ export function getClaudeRows(currentTier, contextView, claudeUsage) {
|
|
|
275
204
|
const fShort =
|
|
276
205
|
hasData && fiveHourPercent != null
|
|
277
206
|
? colorByProvider(fiveHourPercent, `${fiveHourPercent}%`, claudeOrange)
|
|
278
|
-
: dim("
|
|
207
|
+
: dim("--%");
|
|
279
208
|
const wShort =
|
|
280
209
|
hasData && weeklyPercent != null
|
|
281
210
|
? colorByProvider(weeklyPercent, `${weeklyPercent}%`, claudeOrange)
|
|
282
|
-
: dim("
|
|
211
|
+
: dim("--%");
|
|
283
212
|
const quotaSection = `${fShort}${dim("/")}${wShort}`;
|
|
284
213
|
return [{ prefix, left: quotaSection, right: "" }];
|
|
285
214
|
}
|
|
@@ -324,7 +253,10 @@ export function getAccountLabel(
|
|
|
324
253
|
const providerState = accountsState?.providers?.[provider] || {};
|
|
325
254
|
const lastId = providerState.last_selected_id;
|
|
326
255
|
const picked = providerConfig.find((a) => a.id === lastId) ||
|
|
327
|
-
providerConfig[0] || {
|
|
256
|
+
providerConfig[0] || {
|
|
257
|
+
id: `${provider}-main`,
|
|
258
|
+
label: provider === "antigravity" ? "agy" : provider,
|
|
259
|
+
};
|
|
328
260
|
let label = picked.label || picked.id;
|
|
329
261
|
if (codexEmail) label = codexEmail;
|
|
330
262
|
if (label.includes("@")) label = label.split("@")[0];
|
|
@@ -347,15 +279,14 @@ export function getProviderRow(
|
|
|
347
279
|
);
|
|
348
280
|
|
|
349
281
|
const prefix = `${bold(markerColor(marker))}:`;
|
|
350
|
-
if (provider === "antigravity"
|
|
351
|
-
return
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
};
|
|
282
|
+
if (provider === "antigravity") {
|
|
283
|
+
return getAntigravityRow(
|
|
284
|
+
currentTier,
|
|
285
|
+
marker,
|
|
286
|
+
markerColor,
|
|
287
|
+
accountLabel,
|
|
288
|
+
realQuota,
|
|
289
|
+
);
|
|
359
290
|
}
|
|
360
291
|
const provAnsi = CODEX_WHITE;
|
|
361
292
|
const provFn = codexWhite;
|
|
@@ -391,7 +322,7 @@ export function getProviderRow(
|
|
|
391
322
|
};
|
|
392
323
|
}
|
|
393
324
|
}
|
|
394
|
-
return { prefix: minPrefix, left: dim("
|
|
325
|
+
return { prefix: minPrefix, left: dim("--%/--%"), right: "" };
|
|
395
326
|
}
|
|
396
327
|
|
|
397
328
|
if (currentTier === "minimal") {
|
|
@@ -451,16 +382,16 @@ export function getProviderRow(
|
|
|
451
382
|
weekP != null
|
|
452
383
|
? colorByProvider(weekP, formatPercentCell(weekP), provFn)
|
|
453
384
|
: dim(formatPlaceholderPercentCell());
|
|
454
|
-
const fiveReset =
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
385
|
+
const fiveReset = formatResetRemaining(main.primary?.resets_at);
|
|
386
|
+
const weekReset = formatResetRemainingDayHour(
|
|
387
|
+
main.secondary?.resets_at,
|
|
388
|
+
);
|
|
458
389
|
quotaSection = `${dim("5h:")}${fCell} ${dim(formatTimeCell(fiveReset))} ${dim("1w:")}${wCell} ${dim(formatTimeCellDH(weekReset))}`;
|
|
459
390
|
if (main.mixedWindows) quotaSection += dim("*");
|
|
460
391
|
}
|
|
461
392
|
}
|
|
462
393
|
if (!quotaSection) {
|
|
463
|
-
quotaSection = `${dim("5h:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("
|
|
394
|
+
quotaSection = `${dim("5h:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell(""))} ${dim("1w:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCellDH(""))}`;
|
|
464
395
|
}
|
|
465
396
|
const compactRight = [accountLabel ? markerColor(accountLabel) : ""]
|
|
466
397
|
.filter(Boolean)
|
|
@@ -483,9 +414,8 @@ export function getProviderRow(
|
|
|
483
414
|
main.secondary?.used_percent != null
|
|
484
415
|
? clampPercent(main.secondary.used_percent)
|
|
485
416
|
: null;
|
|
486
|
-
const fiveReset = formatResetRemaining(main.primary?.resets_at)
|
|
487
|
-
const weekReset =
|
|
488
|
-
formatResetRemainingDayHour(main.secondary?.resets_at) || "n/a";
|
|
417
|
+
const fiveReset = formatResetRemaining(main.primary?.resets_at);
|
|
418
|
+
const weekReset = formatResetRemainingDayHour(main.secondary?.resets_at);
|
|
489
419
|
const fCell =
|
|
490
420
|
fiveP != null
|
|
491
421
|
? colorByProvider(fiveP, formatPercentCell(fiveP), provFn)
|
|
@@ -513,7 +443,7 @@ export function getProviderRow(
|
|
|
513
443
|
|
|
514
444
|
// 폴백
|
|
515
445
|
if (!quotaSection) {
|
|
516
|
-
quotaSection = `${dim("5h:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("
|
|
446
|
+
quotaSection = `${dim("5h:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell(""))} ${dim("1w:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCellDH(""))}`;
|
|
517
447
|
}
|
|
518
448
|
|
|
519
449
|
const accountSection = `${markerColor(accountLabel)}`;
|
|
@@ -523,3 +453,52 @@ export function getProviderRow(
|
|
|
523
453
|
right: accountSection,
|
|
524
454
|
};
|
|
525
455
|
}
|
|
456
|
+
|
|
457
|
+
// 회색은 로그인 안 된 경우에만 쓴다. GCP 프로젝트 과금은 개인 쿼터가 없을 뿐 정상 상태다.
|
|
458
|
+
function getAntigravityRow(
|
|
459
|
+
currentTier,
|
|
460
|
+
marker,
|
|
461
|
+
markerColor,
|
|
462
|
+
accountLabel,
|
|
463
|
+
quota,
|
|
464
|
+
) {
|
|
465
|
+
const usedPercent = quota?.usedPercent;
|
|
466
|
+
const hasValue = usedPercent != null;
|
|
467
|
+
const loggedIn = quota?.auth != null;
|
|
468
|
+
const project = quota?.auth === "project";
|
|
469
|
+
const tint = loggedIn ? markerColor : dim;
|
|
470
|
+
const prefix = loggedIn ? `${bold(markerColor(marker))}:` : dim(`${marker}:`);
|
|
471
|
+
const stale = quota?.stale ? dim(" [stale]") : "";
|
|
472
|
+
const right = `${tint(accountLabel)}${stale}`;
|
|
473
|
+
const percent = antigravityPercentText(quota);
|
|
474
|
+
if (currentTier === "nano" || currentTier === "micro") {
|
|
475
|
+
return { prefix, left: percent, right };
|
|
476
|
+
}
|
|
477
|
+
const isFull = currentTier === "full";
|
|
478
|
+
const showTime = isFull || currentTier === "compact";
|
|
479
|
+
const reset =
|
|
480
|
+
Date.parse(quota?.resetTime) - Date.now() >= ONE_DAY_MS
|
|
481
|
+
? formatResetRemainingDayHour(quota.resetTime)
|
|
482
|
+
: formatResetRemaining(quota?.resetTime);
|
|
483
|
+
const timeCell = showTime ? ` ${dim(formatTimeCell(reset))}` : "";
|
|
484
|
+
// /usage의 모델별 값에는 5h/1w 식별자가 없으므로 창을 추측하지 않는다.
|
|
485
|
+
// 두 창(5h, 1w) 폭에 맞춰 c, x 행과 구분자 열을 맞춘다.
|
|
486
|
+
const windowWidth =
|
|
487
|
+
"5h:".length +
|
|
488
|
+
(isFull ? GAUGE_WIDTH + 1 : 0) +
|
|
489
|
+
PERCENT_CELL_WIDTH +
|
|
490
|
+
(showTime ? TIME_CELL_INNER_WIDTH + 3 : 0);
|
|
491
|
+
let slot;
|
|
492
|
+
if (project) {
|
|
493
|
+
// 쿼터 대신 과금 방식을 막대 자리(막대가 없는 표시에서는 퍼센트 자리)에 보인다.
|
|
494
|
+
const mark = isFull ? `${markerColor("GCP".padEnd(GAUGE_WIDTH))} ` : "";
|
|
495
|
+
const cell = isFull ? dim(formatPlaceholderPercentCell()) : percent;
|
|
496
|
+
slot = `${dim("--:")}${mark}${cell}${timeCell}`;
|
|
497
|
+
} else {
|
|
498
|
+
const bar = hasValue
|
|
499
|
+
? tierBar(currentTier, usedPercent, GEMINI_BLUE)
|
|
500
|
+
: tierDimBar(currentTier);
|
|
501
|
+
slot = `${dim("--:")}${bar}${percent}${timeCell}`;
|
|
502
|
+
}
|
|
503
|
+
return { prefix, left: padAnsiRight(slot, windowWidth * 2 + 1), right };
|
|
504
|
+
}
|
package/hud/utils.mjs
CHANGED
|
@@ -145,7 +145,7 @@ export function formatPlaceholderPercentCell() {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
export function normalizeTimeToken(value) {
|
|
148
|
-
const text = String(value || "
|
|
148
|
+
const text = String(value || "");
|
|
149
149
|
const hourMinute = text.match(/^(\d+)h(\d+)m$/);
|
|
150
150
|
if (hourMinute) {
|
|
151
151
|
return `${Number(hourMinute[1])}h${String(Number(hourMinute[2])).padStart(2, "0")}m`;
|
|
@@ -157,17 +157,21 @@ export function normalizeTimeToken(value) {
|
|
|
157
157
|
return text;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
// 값이 없는 시간 칸은 단위 모양을 남겨 정상 값과 같은 폭으로 그린다.
|
|
161
|
+
function emptyTimeCell(unit) {
|
|
162
|
+
return unit === "dh" ? "(--d--h)" : "(--h--m)";
|
|
163
|
+
}
|
|
164
|
+
|
|
160
165
|
export function formatTimeCell(value) {
|
|
161
166
|
const text = normalizeTimeToken(value);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return `(${text.padStart(TIME_CELL_INNER_WIDTH, padChar)})`;
|
|
167
|
+
if (!/\d/.test(text)) return emptyTimeCell("hm");
|
|
168
|
+
return `(${text.padStart(TIME_CELL_INNER_WIDTH, "0")})`;
|
|
165
169
|
}
|
|
166
170
|
|
|
167
|
-
// 주간(d/h) 전용 — 최대 7d00h(5자)이므로 공백 불필요
|
|
168
171
|
export function formatTimeCellDH(value) {
|
|
169
172
|
const text = normalizeTimeToken(value);
|
|
170
|
-
|
|
173
|
+
if (!/\d/.test(text)) return emptyTimeCell("dh");
|
|
174
|
+
return `(${text.padStart(TIME_CELL_INNER_WIDTH, " ")})`;
|
|
171
175
|
}
|
|
172
176
|
|
|
173
177
|
export function getCliArgValue(flag) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triflux/core",
|
|
3
|
-
"version": "10.
|
|
4
|
-
"description": "triflux core — CLI routing,
|
|
3
|
+
"version": "10.52.0",
|
|
4
|
+
"description": "triflux core — CLI routing, adapters, account broker. Zero native dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "hub/index.mjs",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./hub/index.mjs",
|
|
9
9
|
"./hub/*": "./hub/*",
|
|
10
|
-
"./mesh/*": "./mesh/*",
|
|
11
10
|
"./scripts/*": "./scripts/*"
|
|
12
11
|
},
|
|
13
12
|
"engines": {
|
|
@@ -15,13 +14,10 @@
|
|
|
15
14
|
},
|
|
16
15
|
"dependencies": {
|
|
17
16
|
"@iarna/toml": "^2.2.5",
|
|
18
|
-
"pino": "^10.3.1",
|
|
19
|
-
"pino-pretty": "^13.1.3",
|
|
20
17
|
"zod": "^4.0.0"
|
|
21
18
|
},
|
|
22
19
|
"files": [
|
|
23
20
|
"hub",
|
|
24
|
-
"mesh",
|
|
25
21
|
"scripts/lib",
|
|
26
22
|
"hooks",
|
|
27
23
|
"hud"
|