@triflux/core 10.1.0 → 10.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hooks/agent-route-guard.mjs +14 -10
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +20 -8
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +267 -35
- package/hooks/hook-registry.json +343 -256
- package/hooks/hooks.json +49 -1
- package/hooks/keyword-rules.json +191 -31
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/permission-safe-allow.mjs +233 -0
- package/hooks/pipeline-stop.mjs +369 -22
- package/hooks/post-tool-tips.mjs +306 -0
- package/hooks/pre-compact-snapshot.mjs +181 -0
- package/hooks/safety-guard.mjs +262 -34
- package/hooks/session-end-cleanup.mjs +345 -0
- package/hooks/session-start-fast.mjs +214 -0
- package/hooks/subagent-tracker.mjs +267 -0
- package/hooks/subagent-verifier.mjs +9 -4
- package/hub/account-broker.mjs +1036 -66
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +96 -58
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +163 -126
- package/hub/bridge.mjs +1051 -290
- package/hub/cli-adapter-base.mjs +321 -97
- package/hub/codex-adapter.mjs +179 -93
- package/hub/codex-compat.mjs +4 -4
- package/hub/codex-preflight.mjs +113 -37
- package/hub/delegator/contracts.mjs +22 -21
- package/hub/delegator/index.mjs +14 -14
- package/hub/delegator/schema/delegator-tools.schema.json +1 -1
- package/hub/delegator/service.mjs +93 -64
- package/hub/delegator/tool-definitions.mjs +35 -35
- package/hub/dynamic-routing-engine.mjs +511 -0
- package/hub/fullcycle.mjs +34 -18
- package/hub/gemini-adapter.mjs +82 -108
- package/hub/hitl.mjs +202 -143
- package/hub/intent.mjs +167 -38
- package/hub/lib/bash-path.mjs +73 -0
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/env-detect.mjs +145 -0
- package/hub/lib/hosts-compat.mjs +319 -0
- package/hub/lib/mcp-response-cache.mjs +239 -0
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +165 -0
- package/hub/lib/phase-manager.mjs +493 -0
- package/hub/lib/process-utils.mjs +797 -104
- package/hub/lib/prompt-tmp.mjs +33 -0
- package/hub/lib/risk-tier.mjs +53 -0
- package/hub/lib/spawn-trace.mjs +561 -0
- package/hub/lib/ssh-command.mjs +44 -24
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/staged-file-detect.mjs +43 -0
- package/hub/lib/state-snapshot.mjs +293 -0
- package/hub/lib/tfx-route-args.mjs +309 -0
- package/hub/lib/timeline-adapter.mjs +190 -0
- package/hub/lib/trace-recorder.mjs +153 -0
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/quota-middleware.mjs +70 -0
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +65 -48
- package/hub/quality/deslop.mjs +70 -49
- package/hub/reflexion.mjs +87 -13
- package/hub/research.mjs +33 -25
- package/hub/router.mjs +941 -791
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +78 -30
- package/hub/routing-snapshot.mjs +261 -0
- package/hub/session-fingerprint.mjs +127 -61
- package/hub/state.mjs +86 -44
- package/hub/team/claude-daemon-control.mjs +1130 -0
- package/hub/team/retry-state-machine.mjs +336 -0
- package/hub/token-mode.mjs +72 -71
- package/hub/workers/worker-utils.mjs +23 -17
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +190 -27
- package/hud/context-monitor.mjs +133 -44
- package/hud/hud-qos-status.mjs +157 -50
- package/hud/mission-board.mjs +56 -0
- package/hud/providers/claude.mjs +398 -114
- package/hud/providers/codex.mjs +96 -21
- package/hud/providers/gemini.mjs +210 -52
- package/hud/renderers.mjs +440 -127
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +81 -39
- package/mesh/index.mjs +69 -0
- package/mesh/mesh-budget.mjs +137 -0
- package/mesh/mesh-heartbeat.mjs +100 -0
- package/mesh/mesh-protocol.mjs +96 -0
- package/mesh/mesh-queue.mjs +163 -0
- package/mesh/mesh-registry.mjs +78 -0
- package/mesh/mesh-router.mjs +77 -0
- package/package.json +5 -1
- package/scripts/lib/agent-json.mjs +27 -0
- package/scripts/lib/async.mjs +174 -0
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/cli-agy.mjs +62 -0
- package/scripts/lib/cli-claude.mjs +78 -0
- package/scripts/lib/cli-codex.mjs +199 -0
- package/scripts/lib/cli-gemini.mjs +37 -0
- package/scripts/lib/codex-recovery.sh +50 -0
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +13 -5
- package/scripts/lib/doctor-env-checks.mjs +121 -0
- package/scripts/lib/dynamic-route-cli.mjs +107 -0
- package/scripts/lib/env-probe.mjs +58 -30
- package/scripts/lib/env.mjs +14 -0
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/hub.mjs +48 -0
- package/scripts/lib/keyword-rules.mjs +49 -20
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +391 -247
- package/scripts/lib/mcp-gateway-health-check.mjs +159 -0
- package/scripts/lib/mcp-gateway-servers.mjs +70 -0
- package/scripts/lib/mcp-gateway-wrapper-check.mjs +35 -0
- package/scripts/lib/mcp-guard-engine.mjs +1281 -115
- package/scripts/lib/mcp-health.mjs +773 -0
- package/scripts/lib/mcp-manifest.mjs +24 -14
- package/scripts/lib/mcp-server-catalog.mjs +355 -118
- package/scripts/lib/pid.mjs +63 -0
- package/scripts/lib/process-utils.mjs +26 -0
- package/scripts/lib/psmux-info.mjs +117 -12
- package/scripts/lib/quota.mjs +47 -0
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-state.mjs +220 -0
- package/scripts/lib/skill-template.mjs +32 -7
- package/scripts/lib/team.mjs +75 -0
- package/scripts/lib/timeout.mjs +66 -0
- package/scripts/lib/tmp.mjs +26 -0
- package/scripts/lib/toml.mjs +113 -0
package/hud/hud-qos-status.mjs
CHANGED
|
@@ -5,46 +5,80 @@
|
|
|
5
5
|
// 각 모듈에서 색상, 터미널, 프로바이더, 렌더러를 가져와 조합한다.
|
|
6
6
|
// ============================================================================
|
|
7
7
|
|
|
8
|
-
import { DIM, RESET, bold, dim, green, claudeOrange, codexWhite, geminiBlue, colorByPercent } from "./colors.mjs";
|
|
9
8
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
bold,
|
|
10
|
+
claudeOrange,
|
|
11
|
+
codexWhite,
|
|
12
|
+
DIM,
|
|
13
|
+
dim,
|
|
14
|
+
geminiBlue,
|
|
15
|
+
green,
|
|
16
|
+
RESET,
|
|
17
|
+
} from "./colors.mjs";
|
|
18
|
+
import {
|
|
19
|
+
ACCOUNTS_CONFIG_PATH,
|
|
20
|
+
ACCOUNTS_STATE_PATH,
|
|
21
|
+
CLAUDE_REFRESH_FLAG,
|
|
22
|
+
CODEX_REFRESH_FLAG,
|
|
23
|
+
GEMINI_FLASH_POOL,
|
|
24
|
+
GEMINI_PRO_POOL,
|
|
25
|
+
GEMINI_REFRESH_FLAG,
|
|
26
|
+
GEMINI_SESSION_REFRESH_FLAG,
|
|
27
|
+
QOS_PATH,
|
|
28
|
+
TFX_PREFLIGHT_CACHE_PATH,
|
|
29
|
+
TFX_PREFLIGHT_CACHE_STALE_MS,
|
|
14
30
|
} from "./constants.mjs";
|
|
15
31
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
buildContextUsageView,
|
|
33
|
+
deriveContextLimit,
|
|
34
|
+
} from "./context-monitor.mjs";
|
|
35
|
+
import { getMissionBoardState } from "./mission-board.mjs";
|
|
20
36
|
// Claude provider
|
|
21
37
|
import {
|
|
22
|
-
|
|
38
|
+
fetchClaudeUsage,
|
|
23
39
|
readClaudeContextSnapshot,
|
|
40
|
+
readClaudeUsageSnapshot,
|
|
41
|
+
scheduleClaudeUsageRefresh,
|
|
24
42
|
} from "./providers/claude.mjs";
|
|
25
|
-
import { buildContextUsageView } from "./context-monitor.mjs";
|
|
26
|
-
|
|
27
43
|
// Codex provider
|
|
28
44
|
import {
|
|
29
|
-
getCodexEmail,
|
|
30
|
-
|
|
45
|
+
getCodexEmail,
|
|
46
|
+
readCodexRateLimitSnapshot,
|
|
47
|
+
refreshCodexRateLimitsCache,
|
|
48
|
+
scheduleCodexRateLimitRefresh,
|
|
31
49
|
} from "./providers/codex.mjs";
|
|
32
|
-
|
|
33
50
|
// Gemini provider
|
|
34
51
|
import {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
buildGeminiAuthContext,
|
|
53
|
+
fetchGeminiQuota,
|
|
54
|
+
getAntigravityEmail,
|
|
55
|
+
getGeminiEmail,
|
|
56
|
+
readGeminiQuotaSnapshot,
|
|
57
|
+
readGeminiSessionSnapshot,
|
|
58
|
+
refreshGeminiSessionCache,
|
|
59
|
+
scheduleGeminiQuotaRefresh,
|
|
60
|
+
scheduleGeminiSessionRefresh,
|
|
39
61
|
} from "./providers/gemini.mjs";
|
|
40
|
-
|
|
41
62
|
// Renderers
|
|
42
63
|
import {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
64
|
+
formatTokenSummary,
|
|
65
|
+
getClaudeRows,
|
|
66
|
+
getMicroLine,
|
|
67
|
+
getProviderRow,
|
|
68
|
+
getTeamRow,
|
|
69
|
+
readLatestBenchmarkDiff,
|
|
70
|
+
readSvAccumulator,
|
|
71
|
+
readTokenSavings,
|
|
72
|
+
renderAlignedRows,
|
|
73
|
+
renderMissionBoard,
|
|
47
74
|
} from "./renderers.mjs";
|
|
75
|
+
import { selectTier } from "./terminal.mjs";
|
|
76
|
+
import {
|
|
77
|
+
getCliArgValue,
|
|
78
|
+
getProviderAccountId,
|
|
79
|
+
readJson,
|
|
80
|
+
readStdinJson,
|
|
81
|
+
} from "./utils.mjs";
|
|
48
82
|
|
|
49
83
|
// ============================================================================
|
|
50
84
|
// 메인
|
|
@@ -78,6 +112,13 @@ async function main() {
|
|
|
78
112
|
const stdinPromise = readStdinJson();
|
|
79
113
|
|
|
80
114
|
const qosProfile = readJson(QOS_PATH, { providers: {} });
|
|
115
|
+
const preflightCache = readJson(TFX_PREFLIGHT_CACHE_PATH, null);
|
|
116
|
+
const preflightTimestamp = Number(preflightCache?.timestamp);
|
|
117
|
+
const preflightFresh =
|
|
118
|
+
Number.isFinite(preflightTimestamp) &&
|
|
119
|
+
Date.now() - preflightTimestamp <= TFX_PREFLIGHT_CACHE_STALE_MS;
|
|
120
|
+
const antigravityReady =
|
|
121
|
+
preflightFresh && preflightCache?.antigravity?.ok === true;
|
|
81
122
|
const accountsConfig = readJson(ACCOUNTS_CONFIG_PATH, { providers: {} });
|
|
82
123
|
const accountsState = readJson(ACCOUNTS_STATE_PATH, { providers: {} });
|
|
83
124
|
const claudeUsageSnapshot = readClaudeUsageSnapshot();
|
|
@@ -85,11 +126,18 @@ async function main() {
|
|
|
85
126
|
if (claudeUsageSnapshot.shouldRefresh) {
|
|
86
127
|
scheduleClaudeUsageRefresh();
|
|
87
128
|
}
|
|
88
|
-
const geminiAccountId = getProviderAccountId(
|
|
129
|
+
const geminiAccountId = getProviderAccountId(
|
|
130
|
+
"gemini",
|
|
131
|
+
accountsConfig,
|
|
132
|
+
accountsState,
|
|
133
|
+
);
|
|
89
134
|
const codexSnapshot = readCodexRateLimitSnapshot();
|
|
90
135
|
const geminiSessionSnapshot = readGeminiSessionSnapshot();
|
|
91
136
|
const geminiAuthContext = buildGeminiAuthContext(geminiAccountId);
|
|
92
|
-
const geminiQuotaSnapshot = readGeminiQuotaSnapshot(
|
|
137
|
+
const geminiQuotaSnapshot = readGeminiQuotaSnapshot(
|
|
138
|
+
geminiAccountId,
|
|
139
|
+
geminiAuthContext,
|
|
140
|
+
);
|
|
93
141
|
if (codexSnapshot.shouldRefresh) {
|
|
94
142
|
scheduleCodexRateLimitRefresh();
|
|
95
143
|
}
|
|
@@ -103,25 +151,31 @@ async function main() {
|
|
|
103
151
|
// 실측 데이터 추출
|
|
104
152
|
const stdin = await stdinPromise;
|
|
105
153
|
const contextView = buildContextUsageView(stdin, contextSnapshot);
|
|
154
|
+
const claudeUsage = claudeUsageSnapshot.data;
|
|
106
155
|
const codexEmail = getCodexEmail();
|
|
107
156
|
const geminiEmail = getGeminiEmail();
|
|
157
|
+
const antigravityEmail = getAntigravityEmail();
|
|
108
158
|
const codexBuckets = codexSnapshot.buckets;
|
|
109
159
|
const geminiSession = geminiSessionSnapshot.session;
|
|
110
160
|
const geminiQuota = geminiQuotaSnapshot.quota;
|
|
161
|
+
const missionBoardState = await getMissionBoardState();
|
|
111
162
|
|
|
112
163
|
// 누적 절약 데이터 읽기
|
|
113
164
|
const svSavings = readTokenSavings();
|
|
114
165
|
const svAccumulator = readSvAccumulator();
|
|
115
|
-
const
|
|
166
|
+
const _totalCostSaved =
|
|
167
|
+
svSavings?.totalSaved || svAccumulator?.totalCostSaved || 0;
|
|
116
168
|
|
|
117
169
|
// 세션/누적 토큰 → context 대비 절약 배수 (개별 provider sv%)
|
|
118
|
-
const ctxCapacity = stdin
|
|
170
|
+
const ctxCapacity = deriveContextLimit(stdin);
|
|
119
171
|
let codexSv = null;
|
|
120
172
|
if (svAccumulator?.codex?.tokens > 0) {
|
|
121
173
|
codexSv = svAccumulator.codex.tokens / ctxCapacity;
|
|
122
174
|
} else if (codexBuckets) {
|
|
123
|
-
const main =
|
|
124
|
-
|
|
175
|
+
const main =
|
|
176
|
+
codexBuckets.codex || codexBuckets[Object.keys(codexBuckets)[0]];
|
|
177
|
+
if (main?.tokens?.total_tokens)
|
|
178
|
+
codexSv = main.tokens.total_tokens / ctxCapacity;
|
|
125
179
|
}
|
|
126
180
|
let geminiSv = null;
|
|
127
181
|
if (svAccumulator?.gemini?.tokens > 0) {
|
|
@@ -134,12 +188,16 @@ async function main() {
|
|
|
134
188
|
// Gemini: 3풀 버킷 추출 (Pro/Flash/Lite — 각 풀 내 모델들은 쿼터 공유)
|
|
135
189
|
const geminiModel = geminiSession?.model || "gemini-3-flash-preview";
|
|
136
190
|
const geminiBuckets = geminiQuota?.buckets || [];
|
|
137
|
-
const geminiBucket =
|
|
138
|
-
|
|
139
|
-
||
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
191
|
+
const geminiBucket =
|
|
192
|
+
geminiBuckets.find((b) => b.modelId === geminiModel) ||
|
|
193
|
+
geminiBuckets.find((b) => b.modelId === "gemini-3-flash-preview") ||
|
|
194
|
+
null;
|
|
195
|
+
const geminiProBucket =
|
|
196
|
+
geminiBuckets.find((b) => GEMINI_PRO_POOL.has(b.modelId)) || null;
|
|
197
|
+
const geminiFlashBucket =
|
|
198
|
+
geminiBuckets.find((b) => GEMINI_FLASH_POOL.has(b.modelId)) || null;
|
|
199
|
+
const geminiLiteBucket =
|
|
200
|
+
geminiBuckets.find((b) => b.modelId?.includes("flash-lite")) || null;
|
|
143
201
|
|
|
144
202
|
// 합산 절약: Codex+Gemini sv% 합산 (컨텍스트 대비 위임 토큰 비율)
|
|
145
203
|
const combinedSvPct = Math.round(((codexSv ?? 0) + (geminiSv ?? 0)) * 100);
|
|
@@ -149,32 +207,76 @@ async function main() {
|
|
|
149
207
|
|
|
150
208
|
// nano tier: 1줄 모드 (극소 폭 또는 알림 배너 대응)
|
|
151
209
|
if (CURRENT_TIER === "nano") {
|
|
152
|
-
const microLine = getMicroLine(
|
|
153
|
-
|
|
210
|
+
const microLine = getMicroLine(
|
|
211
|
+
contextView,
|
|
212
|
+
claudeUsage,
|
|
213
|
+
codexBuckets,
|
|
214
|
+
antigravityReady ? null : geminiSession,
|
|
215
|
+
antigravityReady ? null : geminiBucket,
|
|
216
|
+
antigravityReady ? Math.round((codexSv ?? 0) * 100) : combinedSvPct,
|
|
217
|
+
antigravityReady ? "a" : "g",
|
|
218
|
+
);
|
|
154
219
|
process.stdout.write(`\x1b[0m${microLine}\n`);
|
|
155
220
|
return;
|
|
156
221
|
}
|
|
157
222
|
|
|
158
|
-
const codexQuotaData = codexBuckets
|
|
223
|
+
const codexQuotaData = codexBuckets
|
|
224
|
+
? { type: "codex", buckets: codexBuckets }
|
|
225
|
+
: null;
|
|
159
226
|
const geminiQuotaData = {
|
|
160
227
|
type: "gemini",
|
|
161
228
|
quotaBucket: geminiBucket,
|
|
162
|
-
pools: {
|
|
229
|
+
pools: {
|
|
230
|
+
pro: geminiProBucket,
|
|
231
|
+
flash: geminiFlashBucket,
|
|
232
|
+
lite: geminiLiteBucket,
|
|
233
|
+
},
|
|
163
234
|
session: geminiSession,
|
|
164
235
|
};
|
|
165
236
|
|
|
166
237
|
const rows = [
|
|
167
|
-
...getClaudeRows(CURRENT_TIER, contextView,
|
|
168
|
-
getProviderRow(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
238
|
+
...getClaudeRows(CURRENT_TIER, contextView, claudeUsage, combinedSvPct),
|
|
239
|
+
getProviderRow(
|
|
240
|
+
CURRENT_TIER,
|
|
241
|
+
"codex",
|
|
242
|
+
"x",
|
|
243
|
+
codexWhite,
|
|
244
|
+
qosProfile,
|
|
245
|
+
accountsConfig,
|
|
246
|
+
accountsState,
|
|
247
|
+
codexQuotaData,
|
|
248
|
+
codexEmail,
|
|
249
|
+
codexSv,
|
|
250
|
+
null,
|
|
251
|
+
),
|
|
252
|
+
getProviderRow(
|
|
253
|
+
CURRENT_TIER,
|
|
254
|
+
antigravityReady ? "antigravity" : "gemini",
|
|
255
|
+
antigravityReady ? "a" : "g",
|
|
256
|
+
geminiBlue,
|
|
257
|
+
qosProfile,
|
|
258
|
+
accountsConfig,
|
|
259
|
+
accountsState,
|
|
260
|
+
antigravityReady ? { type: "antigravity" } : geminiQuotaData,
|
|
261
|
+
antigravityReady ? antigravityEmail : geminiEmail,
|
|
262
|
+
antigravityReady ? null : geminiSv,
|
|
263
|
+
null,
|
|
264
|
+
),
|
|
172
265
|
];
|
|
173
266
|
|
|
174
267
|
// tfx-multi 활성 시 팀 상태 행 추가 (v2.2)
|
|
175
268
|
const teamRow = getTeamRow(CURRENT_TIER);
|
|
176
269
|
if (teamRow) rows.push(teamRow);
|
|
177
270
|
|
|
271
|
+
const missionBoard = renderMissionBoard(missionBoardState);
|
|
272
|
+
if (missionBoard) {
|
|
273
|
+
rows.push({
|
|
274
|
+
prefix: bold(claudeOrange("\u25B2")),
|
|
275
|
+
left: missionBoard,
|
|
276
|
+
right: "",
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
178
280
|
// 최근 벤치마크 diff → 토큰 요약 행 추가
|
|
179
281
|
const latestDiff = readLatestBenchmarkDiff();
|
|
180
282
|
if (latestDiff) {
|
|
@@ -186,10 +288,13 @@ async function main() {
|
|
|
186
288
|
|
|
187
289
|
// 비활성 프로바이더 dim 처리: 데이터 없으면 전체 줄 dim
|
|
188
290
|
const codexActive = codexBuckets != null;
|
|
189
|
-
const geminiActive =
|
|
190
|
-
||
|
|
291
|
+
const geminiActive =
|
|
292
|
+
(geminiSession?.total || 0) > 0 ||
|
|
293
|
+
geminiBucket != null ||
|
|
294
|
+
geminiProBucket != null ||
|
|
295
|
+
geminiFlashBucket != null;
|
|
191
296
|
|
|
192
|
-
|
|
297
|
+
const outputLines = renderAlignedRows(rows);
|
|
193
298
|
|
|
194
299
|
// 비활성 줄 dim 래핑 (rows 순서: [claude, codex, gemini])
|
|
195
300
|
if (outputLines.length >= 3) {
|
|
@@ -201,10 +306,12 @@ async function main() {
|
|
|
201
306
|
const contextPercent = contextView.percent;
|
|
202
307
|
const leadingBreaks = contextPercent >= 85 ? "\n\n" : "\n";
|
|
203
308
|
// 줄별 RESET: Claude Code TUI 스타일 간섭 방지 (색상 밝기 버그 수정)
|
|
204
|
-
const resetedLines = outputLines.map(line => `\x1b[0m${line}`);
|
|
309
|
+
const resetedLines = outputLines.map((line) => `\x1b[0m${line}`);
|
|
205
310
|
process.stdout.write(`${leadingBreaks}${resetedLines.join("\n")}\n`);
|
|
206
311
|
}
|
|
207
312
|
|
|
208
313
|
main().catch(() => {
|
|
209
|
-
process.stdout.write(
|
|
314
|
+
process.stdout.write(
|
|
315
|
+
`\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`,
|
|
316
|
+
);
|
|
210
317
|
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// HUD Mission Board — .omc/state/sessions/ 기반 에이전트 진행률 집계
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
|
|
8
|
+
const SESSIONS_DIR = join(homedir(), ".omc", "state", "sessions");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* .omc/state/sessions/ 디렉토리를 읽어 팀 상태를 반환한다.
|
|
12
|
+
* @returns {{ agents: Array<{name: string, status: string, progress: number}>, dagLevel: number, totalProgress: number } | null}
|
|
13
|
+
*/
|
|
14
|
+
export async function getMissionBoardState(sessionsDir = SESSIONS_DIR) {
|
|
15
|
+
let entries;
|
|
16
|
+
try {
|
|
17
|
+
entries = await readdir(sessionsDir);
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const jsonFiles = entries.filter((f) => f.endsWith(".json"));
|
|
23
|
+
if (jsonFiles.length === 0) return null;
|
|
24
|
+
|
|
25
|
+
const agents = [];
|
|
26
|
+
for (const file of jsonFiles) {
|
|
27
|
+
let data;
|
|
28
|
+
try {
|
|
29
|
+
const raw = await readFile(join(sessionsDir, file), "utf8");
|
|
30
|
+
data = JSON.parse(raw);
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const name = data.name ?? file.replace(/\.json$/, "");
|
|
36
|
+
const status = data.status ?? "idle";
|
|
37
|
+
const progress = typeof data.progress === "number" ? data.progress : 0;
|
|
38
|
+
agents.push({ name, status, progress });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (agents.length === 0) return null;
|
|
42
|
+
|
|
43
|
+
const totalProgress =
|
|
44
|
+
agents.length > 0
|
|
45
|
+
? Math.round(
|
|
46
|
+
agents.reduce((sum, a) => sum + a.progress, 0) / agents.length,
|
|
47
|
+
)
|
|
48
|
+
: 0;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
agents,
|
|
52
|
+
// TODO: derive dagLevel from real mission dependency metadata instead of hardcoding 0.
|
|
53
|
+
dagLevel: 0,
|
|
54
|
+
totalProgress,
|
|
55
|
+
};
|
|
56
|
+
}
|