@triflux/core 10.50.1 → 10.51.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 +1 -79
- 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 -9
- package/hub/lib/cto-env.mjs +0 -23
- package/hub/lib/known-errors.json +2 -2
- package/hub/lib/process-utils.mjs +0 -123
- package/hub/lib/spawn-trace.mjs +3 -2
- package/hub/lib/timeout-defaults.mjs +0 -1
- 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/hub/role-contract.mjs +0 -2
- package/hud/cli-policy.mjs +0 -26
- package/hud/colors.mjs +0 -13
- package/hud/constants.mjs +7 -153
- package/hud/context-monitor.mjs +3 -64
- package/hud/hud-qos-status.mjs +54 -264
- package/hud/providers/claude.mjs +4 -16
- package/hud/providers/gemini.mjs +83 -689
- package/hud/renderers.mjs +59 -367
- package/hud/terminal.mjs +1 -63
- package/hud/utils.mjs +2 -26
- package/package.json +1 -4
- package/scripts/lib/agent-route-policy.mjs +162 -14
- package/scripts/lib/claudemd-scanner.mjs +2 -199
- package/scripts/lib/cli-claude.mjs +0 -2
- package/scripts/lib/context.mjs +3 -19
- package/scripts/lib/env-probe.mjs +5 -64
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +25 -104
- package/scripts/lib/session-presence.mjs +1 -1
- package/scripts/lib/skill-template.mjs +0 -271
- package/hub/codex-compat.mjs +0 -12
- package/hub/dynamic-routing-engine.mjs +0 -511
- 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/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/tfx-route-args.mjs +0 -353
- 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/routing-snapshot.mjs +0 -261
- package/hub/token-mode.mjs +0 -228
- package/hud/mission-board.mjs +0 -56
- package/hud/providers/cto.mjs +0 -76
- 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/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/dynamic-route-cli.mjs +0 -107
- 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/hud-qos-status.mjs
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// 각 모듈에서 색상, 터미널, 프로바이더, 렌더러를 가져와 조합한다.
|
|
6
|
-
// ============================================================================
|
|
7
|
-
|
|
8
|
-
import { statSync } from "node:fs";
|
|
3
|
+
import { existsSync, statSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
9
5
|
import { join } from "node:path";
|
|
10
|
-
import {
|
|
11
|
-
resolveHudCliVisibility,
|
|
12
|
-
shouldRenderGeminiFallbackRow,
|
|
13
|
-
} from "./cli-policy.mjs";
|
|
6
|
+
import { resolveHudCliVisibility } from "./cli-policy.mjs";
|
|
14
7
|
import {
|
|
15
8
|
bold,
|
|
16
9
|
claudeOrange,
|
|
@@ -18,355 +11,152 @@ import {
|
|
|
18
11
|
DIM,
|
|
19
12
|
dim,
|
|
20
13
|
geminiBlue,
|
|
21
|
-
green,
|
|
22
14
|
RESET,
|
|
23
15
|
} from "./colors.mjs";
|
|
24
16
|
import {
|
|
25
17
|
ACCOUNTS_CONFIG_PATH,
|
|
26
18
|
ACCOUNTS_STATE_PATH,
|
|
19
|
+
ANTIGRAVITY_REFRESH_FLAG,
|
|
27
20
|
CLAUDE_BAND_MARKER_DIR,
|
|
28
21
|
CLAUDE_BAND_MARKER_TTL_MS,
|
|
29
22
|
CLAUDE_REFRESH_FLAG,
|
|
30
23
|
CODEX_REFRESH_FLAG,
|
|
31
|
-
GEMINI_FLASH_POOL,
|
|
32
|
-
GEMINI_PRO_POOL,
|
|
33
|
-
GEMINI_REFRESH_FLAG,
|
|
34
|
-
GEMINI_SESSION_REFRESH_FLAG,
|
|
35
|
-
QOS_PATH,
|
|
36
|
-
TFX_PREFLIGHT_CACHE_PATH,
|
|
37
|
-
TFX_PREFLIGHT_CACHE_STALE_MS,
|
|
38
24
|
} from "./constants.mjs";
|
|
39
25
|
import { buildContextUsageView } from "./context-monitor.mjs";
|
|
40
|
-
import { getMissionBoardState } from "./mission-board.mjs";
|
|
41
|
-
// Claude provider
|
|
42
26
|
import {
|
|
43
27
|
fetchClaudeUsage,
|
|
44
|
-
readClaudeContextSnapshot,
|
|
45
28
|
readClaudeUsageSnapshot,
|
|
46
29
|
scheduleClaudeUsageRefresh,
|
|
47
30
|
} from "./providers/claude.mjs";
|
|
48
|
-
// Codex provider
|
|
49
31
|
import {
|
|
50
32
|
getCodexEmail,
|
|
33
|
+
hasBrokerCodexAccounts,
|
|
51
34
|
readCodexRateLimitSnapshot,
|
|
52
35
|
refreshCodexRateLimitsCache,
|
|
53
36
|
scheduleCodexRateLimitRefresh,
|
|
54
37
|
} from "./providers/codex.mjs";
|
|
55
|
-
import { readCtoStatus } from "./providers/cto.mjs";
|
|
56
|
-
// Gemini provider
|
|
57
38
|
import {
|
|
58
|
-
buildGeminiAuthContext,
|
|
59
|
-
deriveGeminiFamilyBucket,
|
|
60
|
-
fetchGeminiQuota,
|
|
61
39
|
getAntigravityAccountLabel,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
getGeminiEmail,
|
|
66
|
-
readGeminiQuotaSnapshot,
|
|
67
|
-
readGeminiSessionSnapshot,
|
|
68
|
-
refreshGeminiSessionCache,
|
|
69
|
-
scheduleGeminiQuotaRefresh,
|
|
70
|
-
scheduleGeminiSessionRefresh,
|
|
40
|
+
readAntigravityQuotaSnapshot,
|
|
41
|
+
refreshAntigravityQuotaCache,
|
|
42
|
+
scheduleAntigravityQuotaRefresh,
|
|
71
43
|
} from "./providers/gemini.mjs";
|
|
72
|
-
// Renderers
|
|
73
44
|
import {
|
|
74
|
-
formatTokenSummary,
|
|
75
45
|
getClaudeRows,
|
|
76
46
|
getMicroLine,
|
|
77
47
|
getProviderRow,
|
|
78
|
-
getTeamRow,
|
|
79
|
-
readLatestBenchmarkDiff,
|
|
80
48
|
renderAlignedRows,
|
|
81
|
-
renderMissionBoard,
|
|
82
49
|
} from "./renderers.mjs";
|
|
83
50
|
import { selectTier } from "./terminal.mjs";
|
|
84
|
-
import {
|
|
85
|
-
getCliArgValue,
|
|
86
|
-
getProviderAccountId,
|
|
87
|
-
readJson,
|
|
88
|
-
readStdinJson,
|
|
89
|
-
stripAnsi,
|
|
90
|
-
} from "./utils.mjs";
|
|
51
|
+
import { readJson, readStdinJson } from "./utils.mjs";
|
|
91
52
|
|
|
92
|
-
// ============================================================================
|
|
93
|
-
// 메인
|
|
94
|
-
// ============================================================================
|
|
95
53
|
async function main() {
|
|
96
|
-
// 백그라운드 Claude 사용량 리프레시
|
|
97
54
|
if (process.argv.includes(CLAUDE_REFRESH_FLAG)) {
|
|
98
55
|
await fetchClaudeUsage(true);
|
|
99
56
|
return;
|
|
100
57
|
}
|
|
101
|
-
|
|
102
58
|
if (process.argv.includes(CODEX_REFRESH_FLAG)) {
|
|
103
59
|
await refreshCodexRateLimitsCache();
|
|
104
60
|
return;
|
|
105
61
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
refreshGeminiSessionCache();
|
|
62
|
+
if (process.argv.includes(ANTIGRAVITY_REFRESH_FLAG)) {
|
|
63
|
+
refreshAntigravityQuotaCache();
|
|
109
64
|
return;
|
|
110
65
|
}
|
|
111
66
|
|
|
112
|
-
// 백그라운드 Gemini 쿼터 리프레시 전용 실행 모드
|
|
113
|
-
if (process.argv.includes(GEMINI_REFRESH_FLAG)) {
|
|
114
|
-
const accountId = getCliArgValue("--account") || "gemini-main";
|
|
115
|
-
const authContext = buildGeminiAuthContext(accountId);
|
|
116
|
-
await fetchGeminiQuota(accountId, { authContext, forceRefresh: true });
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// 메인 HUD 경로: 즉시 렌더 우선
|
|
121
67
|
const stdinPromise = readStdinJson();
|
|
122
|
-
|
|
123
|
-
const qosProfile = readJson(QOS_PATH, { providers: {} });
|
|
124
|
-
const preflightCache = readJson(TFX_PREFLIGHT_CACHE_PATH, null);
|
|
125
|
-
const preflightTimestamp = Number(preflightCache?.timestamp);
|
|
126
|
-
const preflightFresh =
|
|
127
|
-
Number.isFinite(preflightTimestamp) &&
|
|
128
|
-
Date.now() - preflightTimestamp <= TFX_PREFLIGHT_CACHE_STALE_MS;
|
|
129
|
-
// machine profile 의 TFX_DISABLE_* 정책. 차단된 CLI 는 행 자체를 그리지 않는다.
|
|
130
|
-
// antigravity 가 꺼지면 antigravityReady 를 강제로 내려서 기존 슬롯 로직이 그대로
|
|
131
|
-
// gemini 폴백 경로를 타게 한다.
|
|
132
68
|
const { showCodex, antigravityAllowed } = resolveHudCliVisibility();
|
|
133
|
-
const antigravityReady =
|
|
134
|
-
antigravityAllowed &&
|
|
135
|
-
preflightFresh &&
|
|
136
|
-
preflightCache?.antigravity?.ok === true;
|
|
137
69
|
const accountsConfig = readJson(ACCOUNTS_CONFIG_PATH, { providers: {} });
|
|
138
70
|
const accountsState = readJson(ACCOUNTS_STATE_PATH, { providers: {} });
|
|
139
71
|
const claudeUsageSnapshot = readClaudeUsageSnapshot();
|
|
140
|
-
const
|
|
141
|
-
|
|
72
|
+
const codexSnapshot = readCodexRateLimitSnapshot();
|
|
73
|
+
const antigravitySnapshot = antigravityAllowed
|
|
74
|
+
? readAntigravityQuotaSnapshot()
|
|
75
|
+
: null;
|
|
76
|
+
if (antigravitySnapshot?.shouldRefresh) scheduleAntigravityQuotaRefresh();
|
|
77
|
+
// 설정이 없는 홈에서는 갱신 프로세스를 시작하지 않는다.
|
|
78
|
+
if (
|
|
79
|
+
claudeUsageSnapshot.shouldRefresh &&
|
|
80
|
+
existsSync(join(homedir(), ".claude"))
|
|
81
|
+
) {
|
|
142
82
|
scheduleClaudeUsageRefresh();
|
|
143
83
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
149
|
-
const codexSnapshot = readCodexRateLimitSnapshot();
|
|
150
|
-
const geminiSessionSnapshot = readGeminiSessionSnapshot();
|
|
151
|
-
const geminiAuthContext = buildGeminiAuthContext(geminiAccountId);
|
|
152
|
-
const geminiQuotaSnapshot = readGeminiQuotaSnapshot(
|
|
153
|
-
geminiAccountId,
|
|
154
|
-
geminiAuthContext,
|
|
155
|
-
);
|
|
156
|
-
if (codexSnapshot.shouldRefresh) {
|
|
84
|
+
if (
|
|
85
|
+
showCodex &&
|
|
86
|
+
codexSnapshot.shouldRefresh &&
|
|
87
|
+
(existsSync(join(homedir(), ".codex")) || hasBrokerCodexAccounts())
|
|
88
|
+
) {
|
|
157
89
|
scheduleCodexRateLimitRefresh();
|
|
158
90
|
}
|
|
159
|
-
if (geminiSessionSnapshot.shouldRefresh) {
|
|
160
|
-
scheduleGeminiSessionRefresh();
|
|
161
|
-
}
|
|
162
|
-
if (geminiQuotaSnapshot.shouldRefresh) {
|
|
163
|
-
scheduleGeminiQuotaRefresh(geminiAccountId);
|
|
164
|
-
}
|
|
165
91
|
|
|
166
|
-
// 실측 데이터 추출
|
|
167
92
|
const stdin = await stdinPromise;
|
|
168
|
-
const contextView = buildContextUsageView(stdin
|
|
93
|
+
const contextView = buildContextUsageView(stdin);
|
|
169
94
|
const claudeUsage = claudeUsageSnapshot.data
|
|
170
95
|
? { ...claudeUsageSnapshot.data, stale: claudeUsageSnapshot.isStale }
|
|
171
|
-
:
|
|
172
|
-
const codexEmail = getCodexEmail();
|
|
173
|
-
const geminiEmail = getGeminiEmail();
|
|
174
|
-
const antigravityAccountLabel = getAntigravityAccountLabel();
|
|
96
|
+
: null;
|
|
175
97
|
const codexBuckets = codexSnapshot.buckets;
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const geminiBucket =
|
|
184
|
-
geminiBuckets.find((b) => b.modelId === geminiModel) ||
|
|
185
|
-
geminiBuckets.find((b) => b.modelId === "gemini-3-flash-preview") ||
|
|
186
|
-
null;
|
|
187
|
-
const geminiProBucket =
|
|
188
|
-
geminiBuckets.find((b) => GEMINI_PRO_POOL.has(b.modelId)) || null;
|
|
189
|
-
const geminiFlashBucket =
|
|
190
|
-
geminiBuckets.find((b) => GEMINI_FLASH_POOL.has(b.modelId)) || null;
|
|
191
|
-
const geminiLiteBucket =
|
|
192
|
-
geminiBuckets.find((b) => b.modelId?.includes("flash-lite")) || null;
|
|
193
|
-
|
|
194
|
-
// Antigravity 현재 장착 모델 + family 통합 bucket (slot1 = 장착 모델 약어, slot2 = Gn family)
|
|
195
|
-
// slot1 quota: 현재 모델이 Gemini family면 family bucket, 아니면(Claude/GPT-OSS) placeholder.
|
|
196
|
-
const antigravityModel = getAntigravityCurrentModel();
|
|
197
|
-
const antigravityAbbrev = getAntigravityModelAbbrev(antigravityModel);
|
|
198
|
-
const antigravityModelFamily = getAntigravityModelFamily(antigravityModel);
|
|
199
|
-
const antigravityFamilyBucket = deriveGeminiFamilyBucket(geminiBuckets);
|
|
200
|
-
const antigravitySlot1Bucket =
|
|
201
|
-
antigravityModelFamily === "gemini" ? antigravityFamilyBucket : null;
|
|
202
|
-
|
|
203
|
-
// 인디케이터 인식 tier 선택 (stdin + Claude 사용량 기반)
|
|
204
|
-
const CURRENT_TIER = selectTier(stdin, claudeUsageSnapshot.data);
|
|
205
|
-
|
|
206
|
-
// antigravity/gemini 슬롯 표시 판정. nano 와 나머지 tier 가 같은 판정을 쓴다.
|
|
207
|
-
const showGeminiRow = shouldRenderGeminiFallbackRow({
|
|
208
|
-
antigravityAllowed,
|
|
209
|
-
antigravityReady,
|
|
210
|
-
geminiEmail,
|
|
211
|
-
geminiBucket,
|
|
212
|
-
geminiSession,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// nano tier: 1줄 모드 (극소 폭 또는 알림 배너 대응)
|
|
216
|
-
if (CURRENT_TIER === "nano") {
|
|
217
|
-
const microLine = getMicroLine(
|
|
218
|
-
contextView,
|
|
219
|
-
claudeUsage,
|
|
220
|
-
codexBuckets,
|
|
221
|
-
antigravityReady ? null : geminiSession,
|
|
222
|
-
antigravityReady ? null : geminiBucket,
|
|
223
|
-
antigravityReady ? "a" : "g",
|
|
224
|
-
{ showCodex, showGemini: showGeminiRow },
|
|
225
|
-
);
|
|
98
|
+
const currentTier = selectTier();
|
|
99
|
+
if (currentTier === "nano") {
|
|
100
|
+
const microLine = getMicroLine(contextView, claudeUsage, codexBuckets, {
|
|
101
|
+
showCodex,
|
|
102
|
+
showAntigravity: antigravityAllowed,
|
|
103
|
+
antigravityQuota: antigravitySnapshot?.data,
|
|
104
|
+
});
|
|
226
105
|
process.stdout.write(`\x1b[0m${microLine}\n`);
|
|
227
106
|
return;
|
|
228
107
|
}
|
|
229
108
|
|
|
230
|
-
const
|
|
231
|
-
?
|
|
232
|
-
:
|
|
233
|
-
const geminiQuotaData = {
|
|
234
|
-
type: "gemini",
|
|
235
|
-
quotaBucket: geminiBucket,
|
|
236
|
-
pools: {
|
|
237
|
-
pro: geminiProBucket,
|
|
238
|
-
flash: geminiFlashBucket,
|
|
239
|
-
lite: geminiLiteBucket,
|
|
240
|
-
},
|
|
241
|
-
session: geminiSession,
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
const rows = [
|
|
245
|
-
...(isClaudeBandActive(stdin?.session_id)
|
|
246
|
-
? []
|
|
247
|
-
: getClaudeRows(CURRENT_TIER, contextView, claudeUsage)),
|
|
248
|
-
];
|
|
249
|
-
|
|
250
|
-
// 정책으로 생략된 행이 있으면 뒤따르는 행의 인덱스가 밀린다. dim 래핑이
|
|
251
|
-
// 하드코딩 인덱스를 쓰지 않도록 실제 위치를 기록해 둔다.
|
|
109
|
+
const rows = isClaudeBandActive(stdin?.session_id)
|
|
110
|
+
? []
|
|
111
|
+
: getClaudeRows(currentTier, contextView, claudeUsage);
|
|
252
112
|
let codexRowIndex = -1;
|
|
253
113
|
if (showCodex) {
|
|
254
114
|
codexRowIndex = rows.length;
|
|
255
115
|
rows.push(
|
|
256
116
|
getProviderRow(
|
|
257
|
-
|
|
117
|
+
currentTier,
|
|
258
118
|
"codex",
|
|
259
119
|
"x",
|
|
260
120
|
codexWhite,
|
|
261
|
-
qosProfile,
|
|
262
121
|
accountsConfig,
|
|
263
122
|
accountsState,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
null,
|
|
123
|
+
codexBuckets ? { type: "codex", buckets: codexBuckets } : null,
|
|
124
|
+
getCodexEmail(),
|
|
267
125
|
),
|
|
268
126
|
);
|
|
269
127
|
}
|
|
270
|
-
|
|
271
|
-
let geminiRowIndex = -1;
|
|
272
|
-
if (showGeminiRow) {
|
|
273
|
-
geminiRowIndex = rows.length;
|
|
128
|
+
if (antigravityAllowed) {
|
|
274
129
|
rows.push(
|
|
275
130
|
getProviderRow(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
131
|
+
currentTier,
|
|
132
|
+
"antigravity",
|
|
133
|
+
"a",
|
|
279
134
|
geminiBlue,
|
|
280
|
-
qosProfile,
|
|
281
135
|
accountsConfig,
|
|
282
136
|
accountsState,
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
type: "antigravity",
|
|
286
|
-
pools: {
|
|
287
|
-
current: antigravitySlot1Bucket,
|
|
288
|
-
gemini_family: antigravityFamilyBucket,
|
|
289
|
-
},
|
|
290
|
-
currentAbbrev: antigravityAbbrev,
|
|
291
|
-
currentModel: antigravityModel,
|
|
292
|
-
currentFamily: antigravityModelFamily,
|
|
293
|
-
}
|
|
294
|
-
: geminiQuotaData,
|
|
295
|
-
antigravityReady ? antigravityAccountLabel : geminiEmail,
|
|
296
|
-
null,
|
|
137
|
+
antigravitySnapshot?.data,
|
|
138
|
+
getAntigravityAccountLabel(),
|
|
297
139
|
),
|
|
298
140
|
);
|
|
299
141
|
}
|
|
300
142
|
|
|
301
|
-
const ctoStatus = readCtoStatus();
|
|
302
|
-
if (ctoStatus) {
|
|
303
|
-
const rightTag =
|
|
304
|
-
CURRENT_TIER === "nano" || CURRENT_TIER === "micro"
|
|
305
|
-
? ""
|
|
306
|
-
: stripAnsi(ctoStatus.rightTag || "").trim();
|
|
307
|
-
rows.push({
|
|
308
|
-
prefix: `${bold(claudeOrange("^"))}:`,
|
|
309
|
-
left: `${dim("cto:")}${stripAnsi(ctoStatus.line)}`,
|
|
310
|
-
right: rightTag ? dim(rightTag) : "",
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// tfx-multi 활성 시 팀 상태 행 추가 (v2.2)
|
|
315
|
-
const teamRow = getTeamRow(CURRENT_TIER);
|
|
316
|
-
if (teamRow) rows.push(teamRow);
|
|
317
|
-
|
|
318
|
-
const missionBoard = renderMissionBoard(missionBoardState);
|
|
319
|
-
if (missionBoard) {
|
|
320
|
-
rows.push({
|
|
321
|
-
prefix: bold(claudeOrange("\u25B2")),
|
|
322
|
-
left: missionBoard,
|
|
323
|
-
right: "",
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// 최근 벤치마크 diff → 토큰 요약 행 추가
|
|
328
|
-
const latestDiff = readLatestBenchmarkDiff();
|
|
329
|
-
if (latestDiff) {
|
|
330
|
-
const summary = formatTokenSummary(latestDiff);
|
|
331
|
-
if (summary) {
|
|
332
|
-
rows.push({ prefix: `${dim("$")}:`, left: summary, right: "" });
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// 비활성 프로바이더 dim 처리: 데이터 없으면 전체 줄 dim
|
|
337
|
-
const codexActive = codexBuckets != null;
|
|
338
|
-
const geminiActive =
|
|
339
|
-
(geminiSession?.total || 0) > 0 ||
|
|
340
|
-
geminiBucket != null ||
|
|
341
|
-
geminiProBucket != null ||
|
|
342
|
-
geminiFlashBucket != null;
|
|
343
|
-
|
|
344
143
|
const outputLines = renderAlignedRows(rows);
|
|
345
|
-
|
|
346
|
-
// 비활성 줄 dim 래핑. 정책으로 생략된 행은 인덱스가 -1 이라 건너뛴다.
|
|
347
|
-
if (!codexActive && outputLines[codexRowIndex] != null) {
|
|
144
|
+
if (!codexBuckets && outputLines[codexRowIndex] != null) {
|
|
348
145
|
outputLines[codexRowIndex] = `${DIM}${outputLines[codexRowIndex]}${RESET}`;
|
|
349
146
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// 선행 개행: 알림 배너(노란 글씨)가 빈 첫 줄에 오도록 → HUD 내용 보호
|
|
356
|
-
const contextPercent = contextView.percent;
|
|
357
|
-
const leadingBreaks = contextPercent >= 85 ? "\n\n" : "\n";
|
|
358
|
-
// 줄별 RESET: Claude Code TUI 스타일 간섭 방지 (색상 밝기 버그 수정)
|
|
359
|
-
const resetedLines = outputLines.map((line) => `\x1b[0m${line}`);
|
|
360
|
-
process.stdout.write(`${leadingBreaks}${resetedLines.join("\n")}\n`);
|
|
147
|
+
// 알림 배너와 TUI 스타일이 HUD 내용에 겹치지 않도록 한다.
|
|
148
|
+
const leadingBreaks = contextView.percent >= 85 ? "\n\n" : "\n";
|
|
149
|
+
const resetLines = outputLines.map((line) => `\x1b[0m${line}`);
|
|
150
|
+
process.stdout.write(`${leadingBreaks}${resetLines.join("\n")}\n`);
|
|
361
151
|
}
|
|
362
152
|
|
|
363
153
|
main().catch(() => {
|
|
364
154
|
process.stdout.write(
|
|
365
|
-
`\x1b[0m${bold(claudeOrange("c"))}: ${dim("5h
|
|
155
|
+
`\x1b[0m${bold(claudeOrange("c"))}: ${dim("5h:--% (n/a) 1w:--% (n/a) | ctx:--%")}\n`,
|
|
366
156
|
);
|
|
367
157
|
});
|
|
368
158
|
|
|
369
|
-
// 프롬프트 위 band
|
|
159
|
+
// 프롬프트 위 band가 같은 정보를 그리는 세션에서는 Claude 행을 생략한다.
|
|
370
160
|
function isClaudeBandActive(sessionId) {
|
|
371
161
|
if (!sessionId) return false;
|
|
372
162
|
try {
|
package/hud/providers/claude.mjs
CHANGED
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
SEVEN_DAY_MS,
|
|
26
26
|
SPAWN_LOCK_TTL_MS,
|
|
27
27
|
} from "../constants.mjs";
|
|
28
|
-
import { readContextMonitorSnapshot } from "../context-monitor.mjs";
|
|
29
28
|
import {
|
|
30
29
|
advanceToNextCycle,
|
|
31
30
|
clampPercent,
|
|
@@ -116,17 +115,14 @@ function normalizeClaudeCredentials(data, source, supportsUsageApi = true) {
|
|
|
116
115
|
};
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
//
|
|
120
|
-
// - CLAUDE_SECURESTORAGE_CONFIG_DIR 가 정의돼 있으면 그 값이 스코프다. 빈 문자열은 기본 디렉터리를
|
|
121
|
-
// 뜻해 접미사를 붙이지 않고, 값이 있으면 NFC 로 정규화한 뒤 해시한다.
|
|
122
|
-
// - 아니면 CLAUDE_CONFIG_DIR 원문(경로 확장·정규화 없이)을 sha256 해 앞 8자리를 붙인다.
|
|
123
|
-
// OMC 격리 세션의 `Claude Code-credentials-<hash>` 항목이 이 규칙으로 만들어진다.
|
|
118
|
+
// 격리된 설정 디렉터리는 기본 Keychain 항목과 다른 서비스 이름을 사용한다.
|
|
124
119
|
export function getKeychainServiceName(env = process.env) {
|
|
125
120
|
const secureDir = env.CLAUDE_SECURESTORAGE_CONFIG_DIR;
|
|
126
121
|
let scope = "";
|
|
127
122
|
if (secureDir !== undefined) {
|
|
128
123
|
scope = secureDir ? secureDir.normalize("NFC") : "";
|
|
129
124
|
} else {
|
|
125
|
+
// CLAUDE_CONFIG_DIR은 정규화하지 않고 빈 문자열은 기본값으로 본다.
|
|
130
126
|
scope = env.CLAUDE_CONFIG_DIR || "";
|
|
131
127
|
}
|
|
132
128
|
if (!scope) return CLAUDE_KEYCHAIN_SERVICE;
|
|
@@ -168,9 +164,7 @@ function readClaudeKeychainRaw(
|
|
|
168
164
|
}
|
|
169
165
|
}
|
|
170
166
|
|
|
171
|
-
//
|
|
172
|
-
// 같은 키만 본다. `-a` 없는 조회는 "계정 없는 항목"이 아니라 같은 service 의 임의 계정 항목을 돌려주고,
|
|
173
|
-
// `add-generic-password` 는 `-a` 가 필수라 그런 항목에는 되쓸 수도 없다(2026-09-21 실측, exit 2).
|
|
167
|
+
// service와 account를 함께 지정해야 다른 계정의 항목을 읽지 않는다.
|
|
174
168
|
export function readClaudeKeychainEntry({
|
|
175
169
|
execFileSyncFn = execFileSync,
|
|
176
170
|
env = process.env,
|
|
@@ -372,9 +366,7 @@ function writeClaudeFileCredentials(
|
|
|
372
366
|
writeCredentialFile(mergeClaudeCredentials(creds, data), filePath);
|
|
373
367
|
}
|
|
374
368
|
|
|
375
|
-
//
|
|
376
|
-
// 계정이 다른 두 저장소가 섞이고(2026-09 실측: 파일=max 계정 만료분, Keychain=pro 계정 현재 로그인),
|
|
377
|
-
// Claude Code 가 실제로 쓰는 Keychain 항목을 옛 계정 토큰으로 덮어쓴다.
|
|
369
|
+
// 자격증명을 읽어 온 저장소에만 써서 다른 계정의 토큰을 덮어쓰지 않는다.
|
|
378
370
|
export function writeBackClaudeCredentials(
|
|
379
371
|
creds,
|
|
380
372
|
{
|
|
@@ -733,7 +725,3 @@ export function scheduleClaudeUsageRefresh() {
|
|
|
733
725
|
});
|
|
734
726
|
}
|
|
735
727
|
}
|
|
736
|
-
|
|
737
|
-
export function readClaudeContextSnapshot() {
|
|
738
|
-
return readContextMonitorSnapshot();
|
|
739
|
-
}
|