@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.
Files changed (90) hide show
  1. package/hooks/agy-session-hook.mjs +11 -56
  2. package/hooks/codex-session-hook.mjs +11 -101
  3. package/hub/bridge.mjs +1 -79
  4. package/hub/cli-adapter-base.mjs +12 -90
  5. package/hub/codex-adapter.mjs +0 -1
  6. package/hub/codex-preflight.mjs +5 -28
  7. package/hub/index.mjs +3 -9
  8. package/hub/lib/cto-env.mjs +0 -23
  9. package/hub/lib/known-errors.json +2 -2
  10. package/hub/lib/process-utils.mjs +0 -123
  11. package/hub/lib/spawn-trace.mjs +3 -2
  12. package/hub/lib/timeout-defaults.mjs +0 -1
  13. package/hub/paths.mjs +0 -6
  14. package/hub/pipeline/index.mjs +0 -190
  15. package/hub/pipeline/transitions.mjs +0 -10
  16. package/hub/reflexion.mjs +1 -84
  17. package/hub/role-contract.mjs +0 -2
  18. package/hud/cli-policy.mjs +0 -26
  19. package/hud/colors.mjs +0 -13
  20. package/hud/constants.mjs +7 -153
  21. package/hud/context-monitor.mjs +3 -64
  22. package/hud/hud-qos-status.mjs +54 -264
  23. package/hud/providers/claude.mjs +4 -16
  24. package/hud/providers/gemini.mjs +83 -689
  25. package/hud/renderers.mjs +59 -367
  26. package/hud/terminal.mjs +1 -63
  27. package/hud/utils.mjs +2 -26
  28. package/package.json +1 -4
  29. package/scripts/lib/agent-route-policy.mjs +162 -14
  30. package/scripts/lib/claudemd-scanner.mjs +2 -199
  31. package/scripts/lib/cli-claude.mjs +0 -2
  32. package/scripts/lib/context.mjs +3 -19
  33. package/scripts/lib/env-probe.mjs +5 -64
  34. package/scripts/lib/gemini-profiles.mjs +2 -69
  35. package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
  36. package/scripts/lib/machine-profile.mjs +3 -17
  37. package/scripts/lib/mcp-filter.mjs +109 -53
  38. package/scripts/lib/mcp-health.mjs +2 -2
  39. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  40. package/scripts/lib/psmux-info.mjs +25 -104
  41. package/scripts/lib/session-presence.mjs +1 -1
  42. package/scripts/lib/skill-template.mjs +0 -271
  43. package/hub/codex-compat.mjs +0 -12
  44. package/hub/dynamic-routing-engine.mjs +0 -511
  45. package/hub/fullcycle.mjs +0 -113
  46. package/hub/gemini-adapter.mjs +0 -174
  47. package/hub/intent.mjs +0 -321
  48. package/hub/lib/mcp-response-cache.mjs +0 -239
  49. package/hub/lib/path-utils.mjs +0 -165
  50. package/hub/lib/risk-tier.mjs +0 -53
  51. package/hub/lib/ssh-command.mjs +0 -231
  52. package/hub/lib/staged-file-detect.mjs +0 -43
  53. package/hub/lib/tfx-route-args.mjs +0 -353
  54. package/hub/lib/timeline-adapter.mjs +0 -190
  55. package/hub/pipeline/gates/confidence.mjs +0 -75
  56. package/hub/pipeline/gates/consensus.mjs +0 -106
  57. package/hub/pipeline/gates/index.mjs +0 -9
  58. package/hub/pipeline/gates/selfcheck.mjs +0 -120
  59. package/hub/quality/deslop.mjs +0 -274
  60. package/hub/research.mjs +0 -155
  61. package/hub/role-control-events.mjs +0 -113
  62. package/hub/routing/complexity.mjs +0 -269
  63. package/hub/routing/index.mjs +0 -122
  64. package/hub/routing/q-learning.mjs +0 -387
  65. package/hub/routing-snapshot.mjs +0 -261
  66. package/hub/token-mode.mjs +0 -228
  67. package/hud/mission-board.mjs +0 -56
  68. package/hud/providers/cto.mjs +0 -76
  69. package/mesh/index.mjs +0 -69
  70. package/mesh/mesh-budget.mjs +0 -137
  71. package/mesh/mesh-heartbeat.mjs +0 -100
  72. package/mesh/mesh-protocol.mjs +0 -96
  73. package/mesh/mesh-queue.mjs +0 -163
  74. package/mesh/mesh-registry.mjs +0 -78
  75. package/mesh/mesh-router.mjs +0 -77
  76. package/scripts/lib/agent-json.mjs +0 -27
  77. package/scripts/lib/async.mjs +0 -174
  78. package/scripts/lib/cli-agy.mjs +0 -85
  79. package/scripts/lib/cli-codex.mjs +0 -62
  80. package/scripts/lib/cli-gemini.mjs +0 -37
  81. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  82. package/scripts/lib/env.mjs +0 -14
  83. package/scripts/lib/hub.mjs +0 -48
  84. package/scripts/lib/pid.mjs +0 -63
  85. package/scripts/lib/quota.mjs +0 -47
  86. package/scripts/lib/skill-state.mjs +0 -220
  87. package/scripts/lib/team.mjs +0 -75
  88. package/scripts/lib/timeout.mjs +0 -66
  89. package/scripts/lib/tmp.mjs +0 -26
  90. package/scripts/lib/toml.mjs +0 -132
@@ -1,16 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ============================================================================
4
- // HUD QoS Status — 메인 오케스트레이터
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
- getAntigravityCurrentModel,
63
- getAntigravityModelAbbrev,
64
- getAntigravityModelFamily,
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
- if (process.argv.includes(GEMINI_SESSION_REFRESH_FLAG)) {
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 contextSnapshot = readClaudeContextSnapshot();
141
- if (claudeUsageSnapshot.shouldRefresh) {
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
- const geminiAccountId = getProviderAccountId(
145
- "gemini",
146
- accountsConfig,
147
- accountsState,
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, contextSnapshot);
93
+ const contextView = buildContextUsageView(stdin);
169
94
  const claudeUsage = claudeUsageSnapshot.data
170
95
  ? { ...claudeUsageSnapshot.data, stale: claudeUsageSnapshot.isStale }
171
- : claudeUsageSnapshot.data;
172
- const codexEmail = getCodexEmail();
173
- const geminiEmail = getGeminiEmail();
174
- const antigravityAccountLabel = getAntigravityAccountLabel();
96
+ : null;
175
97
  const codexBuckets = codexSnapshot.buckets;
176
- const geminiSession = geminiSessionSnapshot.session;
177
- const geminiQuota = geminiQuotaSnapshot.quota;
178
- const missionBoardState = await getMissionBoardState();
179
-
180
- // Gemini: 3풀 버킷 추출 (Pro/Flash/Lite — 각 풀 내 모델들은 쿼터 공유)
181
- const geminiModel = geminiSession?.model || "gemini-3-flash-preview";
182
- const geminiBuckets = geminiQuota?.buckets || [];
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 codexQuotaData = codexBuckets
231
- ? { type: "codex", buckets: codexBuckets }
232
- : null;
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
- CURRENT_TIER,
117
+ currentTier,
258
118
  "codex",
259
119
  "x",
260
120
  codexWhite,
261
- qosProfile,
262
121
  accountsConfig,
263
122
  accountsState,
264
- codexQuotaData,
265
- codexEmail,
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
- CURRENT_TIER,
277
- antigravityReady ? "antigravity" : "gemini",
278
- antigravityReady ? "a" : "g",
131
+ currentTier,
132
+ "antigravity",
133
+ "a",
279
134
  geminiBlue,
280
- qosProfile,
281
135
  accountsConfig,
282
136
  accountsState,
283
- antigravityReady
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
- if (!geminiActive && outputLines[geminiRowIndex] != null) {
351
- outputLines[geminiRowIndex] =
352
- `${DIM}${outputLines[geminiRowIndex]}${RESET}`;
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:")}${green("0%")} ${dim("(n/a)")} ${dim("1w:")}${green("0%")} ${dim("(n/a)")} ${dim("|")} ${dim("ctx:")}${green("0%")}\n`,
155
+ `\x1b[0m${bold(claudeOrange("c"))}: ${dim("5h:--% (n/a) 1w:--% (n/a) | ctx:--%")}\n`,
366
156
  );
367
157
  });
368
158
 
369
- // 프롬프트 위 band 가 같은 정보를 그리는 세션에서는 Claude 행을 중복해 그리지 않는다.
159
+ // 프롬프트 위 band가 같은 정보를 그리는 세션에서는 Claude 행을 생략한다.
370
160
  function isClaudeBandActive(sessionId) {
371
161
  if (!sessionId) return false;
372
162
  try {
@@ -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
- // Claude Code 2.1.x secure-storage 규칙(바이너리 실측, 2026-09-21):
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
- // Keychain 항목은 (service, account) 복합 키다. Claude Code 는 항상 `-a <account>` 로 쓰고 읽으므로
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
- // 되쓰기는 자격증명을 읽어 온 저장소에만 한다. Keychain 출처를 파일에 쓰거나 파일 출처를 Keychain 에 쓰면
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
- }