@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
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
// hub/routing/complexity.mjs — 작업 복잡도 스코어링
|
|
2
|
-
// 작업 설명 텍스트에서 복잡도를 0-1 범위로 계산한다.
|
|
3
|
-
// 외부 의존성 없음 (순수 텍스트 분석)
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 복잡도 지표 키워드 사전
|
|
7
|
-
* 카테고리별 키워드와 가중치 (0-1)
|
|
8
|
-
*/
|
|
9
|
-
const COMPLEXITY_INDICATORS = {
|
|
10
|
-
// 높은 복잡도 (0.7-1.0)
|
|
11
|
-
high: {
|
|
12
|
-
keywords: [
|
|
13
|
-
"refactor",
|
|
14
|
-
"architecture",
|
|
15
|
-
"security",
|
|
16
|
-
"migration",
|
|
17
|
-
"distributed",
|
|
18
|
-
"concurrent",
|
|
19
|
-
"parallel",
|
|
20
|
-
"optimization",
|
|
21
|
-
"performance",
|
|
22
|
-
"scalability",
|
|
23
|
-
"cryptograph",
|
|
24
|
-
"encryption",
|
|
25
|
-
"authentication",
|
|
26
|
-
"authorization",
|
|
27
|
-
"database schema",
|
|
28
|
-
"data model",
|
|
29
|
-
"state machine",
|
|
30
|
-
"event-driven",
|
|
31
|
-
"microservice",
|
|
32
|
-
"orchestrat",
|
|
33
|
-
"pipeline",
|
|
34
|
-
"workflow",
|
|
35
|
-
// 한국어
|
|
36
|
-
"리팩터링",
|
|
37
|
-
"리팩토링",
|
|
38
|
-
"아키텍처",
|
|
39
|
-
"보안",
|
|
40
|
-
"마이그레이션",
|
|
41
|
-
"분산",
|
|
42
|
-
"동시성",
|
|
43
|
-
"병렬",
|
|
44
|
-
"최적화",
|
|
45
|
-
"성능",
|
|
46
|
-
"확장성",
|
|
47
|
-
"암호화",
|
|
48
|
-
"인증",
|
|
49
|
-
"인가",
|
|
50
|
-
"데이터베이스 스키마",
|
|
51
|
-
"데이터 모델",
|
|
52
|
-
"상태 머신",
|
|
53
|
-
"이벤트 드리븐",
|
|
54
|
-
"마이크로서비스",
|
|
55
|
-
"오케스트레이션",
|
|
56
|
-
],
|
|
57
|
-
weight: 0.85,
|
|
58
|
-
},
|
|
59
|
-
// 중간 복잡도 (0.4-0.7)
|
|
60
|
-
medium: {
|
|
61
|
-
keywords: [
|
|
62
|
-
"implement",
|
|
63
|
-
"integrate",
|
|
64
|
-
"api",
|
|
65
|
-
"endpoint",
|
|
66
|
-
"middleware",
|
|
67
|
-
"validation",
|
|
68
|
-
"error handling",
|
|
69
|
-
"testing",
|
|
70
|
-
"debug",
|
|
71
|
-
"fix bug",
|
|
72
|
-
"configuration",
|
|
73
|
-
"deploy",
|
|
74
|
-
"ci/cd",
|
|
75
|
-
"docker",
|
|
76
|
-
"container",
|
|
77
|
-
"cache",
|
|
78
|
-
"queue",
|
|
79
|
-
"webhook",
|
|
80
|
-
"notification",
|
|
81
|
-
"logging",
|
|
82
|
-
// 한국어
|
|
83
|
-
"구현",
|
|
84
|
-
"통합",
|
|
85
|
-
"엔드포인트",
|
|
86
|
-
"미들웨어",
|
|
87
|
-
"유효성 검사",
|
|
88
|
-
"에러 처리",
|
|
89
|
-
"오류 처리",
|
|
90
|
-
"테스트",
|
|
91
|
-
"디버깅",
|
|
92
|
-
"버그 수정",
|
|
93
|
-
"설정",
|
|
94
|
-
"배포",
|
|
95
|
-
"컨테이너",
|
|
96
|
-
"캐시",
|
|
97
|
-
"알림",
|
|
98
|
-
"로깅",
|
|
99
|
-
],
|
|
100
|
-
weight: 0.55,
|
|
101
|
-
},
|
|
102
|
-
// 낮은 복잡도 (0.1-0.4)
|
|
103
|
-
low: {
|
|
104
|
-
keywords: [
|
|
105
|
-
"readme",
|
|
106
|
-
"comment",
|
|
107
|
-
"typo",
|
|
108
|
-
"rename",
|
|
109
|
-
"format",
|
|
110
|
-
"lint",
|
|
111
|
-
"update version",
|
|
112
|
-
"bump",
|
|
113
|
-
"add dependency",
|
|
114
|
-
"install",
|
|
115
|
-
"simple",
|
|
116
|
-
"trivial",
|
|
117
|
-
"minor",
|
|
118
|
-
"small change",
|
|
119
|
-
"one-liner",
|
|
120
|
-
// 한국어
|
|
121
|
-
"문서화",
|
|
122
|
-
"주석",
|
|
123
|
-
"오타",
|
|
124
|
-
"이름 변경",
|
|
125
|
-
"포맷",
|
|
126
|
-
"버전 업데이트",
|
|
127
|
-
"의존성 추가",
|
|
128
|
-
"설치",
|
|
129
|
-
"간단",
|
|
130
|
-
"사소한",
|
|
131
|
-
"소규모",
|
|
132
|
-
"한 줄",
|
|
133
|
-
],
|
|
134
|
-
weight: 0.2,
|
|
135
|
-
},
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* 어휘 복잡도 계산 (20%)
|
|
140
|
-
* 고유 단어 비율 + 평균 단어 길이 기반
|
|
141
|
-
* @param {string[]} words
|
|
142
|
-
* @returns {number} 0-1
|
|
143
|
-
*/
|
|
144
|
-
function lexicalComplexity(words) {
|
|
145
|
-
if (words.length === 0) return 0;
|
|
146
|
-
const unique = new Set(words);
|
|
147
|
-
const typeTokenRatio = unique.size / words.length;
|
|
148
|
-
const avgWordLen = words.reduce((sum, w) => sum + w.length, 0) / words.length;
|
|
149
|
-
// 긴 단어(기술 용어)가 많을수록 복잡
|
|
150
|
-
const lenScore = Math.min(avgWordLen / 10, 1);
|
|
151
|
-
return typeTokenRatio * 0.5 + lenScore * 0.5;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* 시맨틱 깊이 계산 (35%)
|
|
156
|
-
* 키워드 사전 매칭 기반
|
|
157
|
-
* @param {string} text
|
|
158
|
-
* @returns {number} 0-1
|
|
159
|
-
*/
|
|
160
|
-
function semanticDepth(text) {
|
|
161
|
-
const lower = text.toLowerCase();
|
|
162
|
-
let maxWeight = 0;
|
|
163
|
-
let matchCount = 0;
|
|
164
|
-
|
|
165
|
-
for (const [, category] of Object.entries(COMPLEXITY_INDICATORS)) {
|
|
166
|
-
for (const kw of category.keywords) {
|
|
167
|
-
if (lower.includes(kw)) {
|
|
168
|
-
matchCount++;
|
|
169
|
-
if (category.weight > maxWeight) maxWeight = category.weight;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// 매칭 키워드 수와 최고 가중치 조합
|
|
174
|
-
const countScore = Math.min(matchCount / 5, 1);
|
|
175
|
-
return maxWeight * 0.6 + countScore * 0.4;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* 작업 범위 계산 (25%)
|
|
180
|
-
* 문장 수, 줄 수, 파일/경로 참조 기반
|
|
181
|
-
* @param {string} text
|
|
182
|
-
* @returns {number} 0-1
|
|
183
|
-
*/
|
|
184
|
-
function taskScope(text) {
|
|
185
|
-
const lines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
186
|
-
const sentences = text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
|
|
187
|
-
const fileRefs = (text.match(/[\w\-/]+\.\w{1,5}/g) || []).length;
|
|
188
|
-
|
|
189
|
-
const lineScore = Math.min(lines.length / 20, 1);
|
|
190
|
-
const sentenceScore = Math.min(sentences.length / 10, 1);
|
|
191
|
-
const fileScore = Math.min(fileRefs / 5, 1);
|
|
192
|
-
|
|
193
|
-
return lineScore * 0.3 + sentenceScore * 0.3 + fileScore * 0.4;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* 불확실성 계산 (20%)
|
|
198
|
-
* 모호한 표현, 질문, 조건문 기반
|
|
199
|
-
* @param {string} text
|
|
200
|
-
* @returns {number} 0-1
|
|
201
|
-
*/
|
|
202
|
-
function uncertainty(text) {
|
|
203
|
-
const lower = text.toLowerCase();
|
|
204
|
-
const uncertainWords = [
|
|
205
|
-
"maybe",
|
|
206
|
-
"perhaps",
|
|
207
|
-
"might",
|
|
208
|
-
"could",
|
|
209
|
-
"possibly",
|
|
210
|
-
"unclear",
|
|
211
|
-
"not sure",
|
|
212
|
-
"investigate",
|
|
213
|
-
"explore",
|
|
214
|
-
"research",
|
|
215
|
-
"try",
|
|
216
|
-
"consider",
|
|
217
|
-
"evaluate",
|
|
218
|
-
"assess",
|
|
219
|
-
"determine",
|
|
220
|
-
"figure out",
|
|
221
|
-
];
|
|
222
|
-
let count = 0;
|
|
223
|
-
for (const w of uncertainWords) {
|
|
224
|
-
if (lower.includes(w)) count++;
|
|
225
|
-
}
|
|
226
|
-
const questions = (text.match(/\?/g) || []).length;
|
|
227
|
-
const wordScore = Math.min(count / 4, 1);
|
|
228
|
-
const questionScore = Math.min(questions / 3, 1);
|
|
229
|
-
return wordScore * 0.6 + questionScore * 0.4;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* 작업 복잡도 스코어링
|
|
234
|
-
* @param {string} taskDescription — 작업 설명 텍스트
|
|
235
|
-
* @returns {{ score: number, breakdown: { lexical: number, semantic: number, scope: number, uncertainty: number } }}
|
|
236
|
-
*/
|
|
237
|
-
export function scoreComplexity(taskDescription) {
|
|
238
|
-
if (!taskDescription || typeof taskDescription !== "string") {
|
|
239
|
-
return {
|
|
240
|
-
score: 0,
|
|
241
|
-
breakdown: { lexical: 0, semantic: 0, scope: 0, uncertainty: 0 },
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const words = taskDescription
|
|
246
|
-
.toLowerCase()
|
|
247
|
-
.split(/\s+/)
|
|
248
|
-
.filter((w) => w.length > 0);
|
|
249
|
-
const lexical = lexicalComplexity(words);
|
|
250
|
-
const semantic = semanticDepth(taskDescription);
|
|
251
|
-
const scope = taskScope(taskDescription);
|
|
252
|
-
const uncertain = uncertainty(taskDescription);
|
|
253
|
-
|
|
254
|
-
// 가중 합산: 어휘(20%) + 시맨틱(35%) + 범위(25%) + 불확실성(20%)
|
|
255
|
-
const score = Math.min(
|
|
256
|
-
lexical * 0.2 + semantic * 0.35 + scope * 0.25 + uncertain * 0.2,
|
|
257
|
-
1,
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
return {
|
|
261
|
-
score: Math.round(score * 1000) / 1000,
|
|
262
|
-
breakdown: {
|
|
263
|
-
lexical: Math.round(lexical * 1000) / 1000,
|
|
264
|
-
semantic: Math.round(semantic * 1000) / 1000,
|
|
265
|
-
scope: Math.round(scope * 1000) / 1000,
|
|
266
|
-
uncertainty: Math.round(uncertain * 1000) / 1000,
|
|
267
|
-
},
|
|
268
|
-
};
|
|
269
|
-
}
|
package/hub/routing/index.mjs
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// hub/routing/index.mjs — 통합 라우팅 진입점
|
|
2
|
-
// Q-Learning 동적 라우팅 + agent-map.json 정적 폴백
|
|
3
|
-
// 환경변수 TRIFLUX_DYNAMIC_ROUTING=true 로 옵트인 (기본 false)
|
|
4
|
-
|
|
5
|
-
import { createRequire } from "node:module";
|
|
6
|
-
import { scoreComplexity } from "./complexity.mjs";
|
|
7
|
-
import { QLearningRouter } from "./q-learning.mjs";
|
|
8
|
-
|
|
9
|
-
const _require = createRequire(import.meta.url);
|
|
10
|
-
|
|
11
|
-
/** agent-map.json 정적 매핑 */
|
|
12
|
-
let AGENT_MAP;
|
|
13
|
-
try {
|
|
14
|
-
AGENT_MAP = _require("../team/agent-map.json");
|
|
15
|
-
} catch {
|
|
16
|
-
AGENT_MAP = {};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** 싱글턴 라우터 인스턴스 (lazy init) */
|
|
20
|
-
let _router = null;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 라우터 인스턴스 획득 (lazy singleton)
|
|
24
|
-
* @returns {QLearningRouter}
|
|
25
|
-
*/
|
|
26
|
-
function getRouter() {
|
|
27
|
-
if (!_router) {
|
|
28
|
-
_router = new QLearningRouter();
|
|
29
|
-
_router.load();
|
|
30
|
-
}
|
|
31
|
-
return _router;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 동적 라우팅 활성화 여부
|
|
36
|
-
* @returns {boolean}
|
|
37
|
-
*/
|
|
38
|
-
function isDynamicRoutingEnabled() {
|
|
39
|
-
const env = process.env.TRIFLUX_DYNAMIC_ROUTING;
|
|
40
|
-
return env === "true" || env === "1";
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 통합 라우팅 결정
|
|
45
|
-
* 우선순위: Q-Learning 예측 (신뢰도 >= 0.6) -> agent-map.json 기본값
|
|
46
|
-
*
|
|
47
|
-
* @param {string} agentType — 에이전트 역할명 ("executor", "designer" 등)
|
|
48
|
-
* @param {string} [taskDescription=''] — 작업 설명 (동적 라우팅용)
|
|
49
|
-
* @returns {{ cliType: string, source: 'dynamic' | 'static', confidence: number, complexity: number }}
|
|
50
|
-
*/
|
|
51
|
-
export function resolveRoute(agentType, taskDescription = "") {
|
|
52
|
-
// 정적 기본값
|
|
53
|
-
const staticCli = AGENT_MAP[agentType] || agentType;
|
|
54
|
-
const { score: complexity } = scoreComplexity(taskDescription);
|
|
55
|
-
|
|
56
|
-
// 동적 라우팅 비활성화 시 정적 매핑 반환
|
|
57
|
-
if (!isDynamicRoutingEnabled()) {
|
|
58
|
-
return { cliType: staticCli, source: "static", confidence: 1, complexity };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 작업 설명 없으면 정적 폴백
|
|
62
|
-
if (!taskDescription || taskDescription.trim().length === 0) {
|
|
63
|
-
return { cliType: staticCli, source: "static", confidence: 1, complexity };
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const router = getRouter();
|
|
67
|
-
const prediction = router.predict(taskDescription);
|
|
68
|
-
|
|
69
|
-
// 신뢰도 기준 미달 시 정적 폴백
|
|
70
|
-
if (prediction.confidence < 0.6) {
|
|
71
|
-
return {
|
|
72
|
-
cliType: staticCli,
|
|
73
|
-
source: "static",
|
|
74
|
-
confidence: prediction.confidence,
|
|
75
|
-
complexity,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
cliType: prediction.action,
|
|
81
|
-
source: "dynamic",
|
|
82
|
-
confidence: prediction.confidence,
|
|
83
|
-
complexity,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 라우팅 피드백 업데이트
|
|
89
|
-
* @param {string} taskDescription — 작업 설명
|
|
90
|
-
* @param {string} action — 수행한 CLI 타입
|
|
91
|
-
* @param {number} reward — 보상 (-1 ~ 1)
|
|
92
|
-
* @param {boolean} [persist=true] — 영속화 여부
|
|
93
|
-
*/
|
|
94
|
-
export function updateRoute(taskDescription, action, reward, persist = true) {
|
|
95
|
-
if (!isDynamicRoutingEnabled()) return;
|
|
96
|
-
|
|
97
|
-
const router = getRouter();
|
|
98
|
-
router.update(taskDescription, action, reward);
|
|
99
|
-
if (persist) router.save();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 라우터 상태 조회 (진단용)
|
|
104
|
-
* @returns {{ enabled: boolean, epsilon: number, totalUpdates: number, stateCount: number }}
|
|
105
|
-
*/
|
|
106
|
-
export function routerStatus() {
|
|
107
|
-
const enabled = isDynamicRoutingEnabled();
|
|
108
|
-
if (!enabled) {
|
|
109
|
-
return { enabled, epsilon: 0, totalUpdates: 0, stateCount: 0 };
|
|
110
|
-
}
|
|
111
|
-
const router = getRouter();
|
|
112
|
-
return {
|
|
113
|
-
enabled,
|
|
114
|
-
epsilon: router.epsilon,
|
|
115
|
-
totalUpdates: router.totalUpdates,
|
|
116
|
-
stateCount: router.stateCount,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// re-export for convenience
|
|
121
|
-
export { scoreComplexity } from "./complexity.mjs";
|
|
122
|
-
export { ACTIONS, QLearningRouter } from "./q-learning.mjs";
|