@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,174 +0,0 @@
1
- // hub/gemini-adapter.mjs — legacy Gemini adapter compatibility layer
2
- // The "gemini" route is retained as an alias, but execution is Antigravity/agy.
3
-
4
- import { mkdirSync } from "node:fs";
5
- import { tmpdir } from "node:os";
6
- import { join } from "node:path";
7
- import {
8
- resolveGeminiModel,
9
- resolveGeminiProfileForPurpose,
10
- } from "../scripts/lib/gemini-profiles.mjs";
11
- import {
12
- executeWithCircuitBroker,
13
- normalizePathForShell,
14
- runProcess,
15
- } from "./cli-adapter-base.mjs";
16
- import { isActivityLifecycleEnabled } from "./lib/worker-lifecycle.mjs";
17
- import { whichCommandAsync } from "./platform.mjs";
18
-
19
- function shellSingleQuote(value) {
20
- return `'${String(value).replace(/'/g, "'\\''")}'`;
21
- }
22
-
23
- // ── Antigravity stall inference ─────────────────────────────────
24
-
25
- function inferStallMode(stdout, stderr) {
26
- const text = `${stdout}\n${stderr}`.toLowerCase();
27
- if (/(rate.?limit|quota|resource.?exhaust|429)/u.test(text))
28
- return "rate_limited";
29
- if (
30
- /(unauthorized|forbidden|auth|login|token|credential|api.?key)/u.test(text)
31
- )
32
- return "auth_stall";
33
- if (/\bmcp\b|playwright|tavily|brave|sequential|server/u.test(text))
34
- return "mcp_stall";
35
- return "timeout";
36
- }
37
-
38
- // ── Preflight ───────────────────────────────────────────────────
39
-
40
- async function runPreflight(opts = {}) {
41
- const agyPath = await whichCommandAsync("agy");
42
- if (!agyPath) {
43
- return {
44
- agyPath: null,
45
- warnings: [
46
- "Antigravity CLI not found. Install Antigravity and ensure `agy` is available on PATH.",
47
- ],
48
- excludeMcpServers: [],
49
- ok: false,
50
- };
51
- }
52
-
53
- const warnings = [];
54
- const excludeMcpServers = [];
55
-
56
- for (const name of Array.isArray(opts.mcpServers) ? opts.mcpServers : []) {
57
- const server = String(name ?? "").trim();
58
- if (!server) continue;
59
- // Antigravity MCP health는 best-effort: 실행 시점 probe는 수행하지 않음.
60
- }
61
-
62
- return { agyPath, warnings, excludeMcpServers, ok: true };
63
- }
64
-
65
- // ── Command building ────────────────────────────────────────────
66
-
67
- function buildGeminiCommand(prompt, resultFile, opts = {}) {
68
- // agy 의 --print 는 값(프롬프트)을 받는 플래그다. 1.1.27 부터 stdin 프롬프트는
69
- // "empty prompt" 로 거부되므로 프롬프트를 --print 의 값으로, 맨 끝에 넘긴다.
70
- const parts = ["agy", "--dangerously-skip-permissions"];
71
- if (typeof opts.model === "string" && opts.model.trim()) {
72
- parts.push("--model", shellSingleQuote(opts.model.trim()));
73
- }
74
- parts.push("--print", shellSingleQuote(prompt));
75
-
76
- if (resultFile) {
77
- return `${parts.join(" ")} > ${shellSingleQuote(normalizePathForShell(resultFile))} 2>${shellSingleQuote(normalizePathForShell(resultFile + ".err"))}`;
78
- }
79
-
80
- return parts.join(" ");
81
- }
82
-
83
- function resolveAntigravityModel(opts = {}) {
84
- // effort 는 역할별 SSOT(scripts/lib/gemini-profiles.mjs). 명시 model 이 우선한다.
85
- const explicit = typeof opts.model === "string" ? opts.model.trim() : "";
86
- if (explicit)
87
- return resolveGeminiModel(explicit, {
88
- profilesPath: opts.geminiProfilesPath,
89
- });
90
- if (!opts.role && !opts.agent) return "";
91
- return resolveGeminiModel(
92
- resolveGeminiProfileForPurpose(opts.role || opts.agent),
93
- {
94
- profilesPath: opts.geminiProfilesPath,
95
- },
96
- );
97
- }
98
-
99
- function buildAttempts(opts, preflight) {
100
- const timeout = Number.isFinite(opts.timeout) ? opts.timeout : 900_000;
101
- const base = {
102
- timeout,
103
- model: resolveAntigravityModel(opts),
104
- allowedMcpServers: Array.isArray(opts.mcpServers)
105
- ? [...opts.mcpServers]
106
- : [],
107
- excludeMcpServers: [...(preflight.excludeMcpServers || [])],
108
- };
109
- if (opts.retryOnFail === false) return [base];
110
- const retryTimeout = isActivityLifecycleEnabled() ? timeout : timeout * 2;
111
- return [base, { ...base, timeout: retryTimeout, allowedMcpServers: [] }];
112
- }
113
-
114
- // ── Public: buildExecArgs ───────────────────────────────────────
115
-
116
- export function buildExecArgs(opts = {}) {
117
- const prompt = typeof opts.prompt === "string" ? opts.prompt : "";
118
- return buildGeminiCommand(prompt, opts.resultFile || null, {
119
- model: resolveAntigravityModel(opts),
120
- allowedMcpServers: opts.mcpServers,
121
- });
122
- }
123
-
124
- // ── Execution ───────────────────────────────────────────────────
125
-
126
- async function runGemini(prompt, workdir, preflight, attempt, lease) {
127
- const dir = join(tmpdir(), "triflux-antigravity-exec");
128
- mkdirSync(dir, { recursive: true });
129
- const resultFile = join(
130
- dir,
131
- `agy-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`,
132
- );
133
- const command = buildGeminiCommand(prompt, resultFile, {
134
- model: attempt.model,
135
- allowedMcpServers: attempt.allowedMcpServers,
136
- excludeMcpServers: attempt.excludeMcpServers,
137
- });
138
- // PRD A1: lease.env 가 있으면 spawn env 에 적용 (예: GOOGLE_API_KEY 등 account-specific
139
- // 환경변수). lease 가 null 이면 default 동작 유지 (부모 env inherit).
140
- const spawnEnv =
141
- lease?.env && typeof lease.env === "object"
142
- ? { ...process.env, ...lease.env }
143
- : undefined;
144
- return runProcess(command, workdir, attempt.timeout, {
145
- resultFile,
146
- inferStallMode,
147
- spawnEnv,
148
- });
149
- }
150
-
151
- // ── Public API ──────────────────────────────────────────────────
152
-
153
- export async function getCircuitState() {
154
- const brokerMod = await import("./account-broker.mjs");
155
- if (!brokerMod.broker) return { state: "closed", failures: [] };
156
- const snap = brokerMod.broker
157
- .snapshot()
158
- .filter((a) => a.provider === "gemini");
159
- return snap.length
160
- ? { state: snap[0].circuitState, accounts: snap }
161
- : { state: "closed", failures: [] };
162
- }
163
-
164
- export function execute(opts = {}) {
165
- return executeWithCircuitBroker({
166
- // Account-broker still stores this compatibility bucket as "gemini";
167
- // execution itself is routed to agy above.
168
- provider: "gemini",
169
- runFn: runGemini,
170
- preflightFn: (o) => runPreflight({ mcpServers: o.mcpServers }),
171
- buildAttemptsFn: buildAttempts,
172
- opts,
173
- });
174
- }
package/hub/intent.mjs DELETED
@@ -1,321 +0,0 @@
1
- // hub/intent.mjs — Intent Classification Engine
2
- // 사용자 요청의 "진짜 의도"를 분석 → 카테고리 분류 → 최적 에이전트/모델 자동 선택
3
-
4
- import { execFileSync } from "node:child_process";
5
- import crypto from "node:crypto";
6
- import { resolveCodexAgentPolicy } from "../scripts/lib/agent-route-policy.mjs";
7
- import { whichCommand } from "./platform.mjs";
8
-
9
- /** 캐시 엔트리: { category, confidence, ts } */
10
- const _intentCache = new Map();
11
- const CACHE_TTL_MS = 5 * 60 * 1000; // 5분
12
-
13
- /** codex 설치 여부 (프로세스당 1회 확인) */
14
- let _codexAvailable = null;
15
-
16
- /** @experimental 런타임 미연결 — 향후 통합 예정 */
17
- function _isCodexAvailable() {
18
- if (_codexAvailable !== null) return _codexAvailable;
19
- _codexAvailable = Boolean(whichCommand("codex"));
20
- return _codexAvailable;
21
- }
22
-
23
- function _promptHash(prompt) {
24
- return crypto.createHash("md5").update(prompt).digest("hex");
25
- }
26
-
27
- function _getCached(hash) {
28
- const entry = _intentCache.get(hash);
29
- if (!entry) return null;
30
- if (Date.now() - entry.ts > CACHE_TTL_MS) {
31
- _intentCache.delete(hash);
32
- return null;
33
- }
34
- return entry;
35
- }
36
-
37
- function _tryCodexClassify(prompt) {
38
- try {
39
- const raw = execFileSync(
40
- "codex",
41
- ["exec", `Classify intent: ${prompt}. Reply JSON: {intent, confidence}`],
42
- { timeout: 8000, encoding: "utf8" },
43
- );
44
- // JSON 블록 추출 (응답에 다른 텍스트가 섞일 수 있음)
45
- const match = raw.match(/\{[\s\S]*?\}/);
46
- if (!match) return null;
47
- const parsed = JSON.parse(match[0]);
48
- const intent = typeof parsed.intent === "string" ? parsed.intent : null;
49
- const confidence =
50
- typeof parsed.confidence === "number" ? parsed.confidence : null;
51
- if (!intent || confidence === null) return null;
52
- // intent가 알려진 카테고리여야 함
53
- if (!INTENT_CATEGORIES[intent]) return null;
54
- return { category: intent, confidence };
55
- } catch {
56
- return null;
57
- }
58
- }
59
-
60
- /**
61
- * @experimental
62
- * triflux 특화 의도 카테고리 (10개)
63
- */
64
- export const INTENT_CATEGORIES = {
65
- implement: { agent: "executor", mcp: "implement" },
66
- debug: { agent: "debugger", mcp: "implement" },
67
- analyze: { agent: "analyst", mcp: "analyze" },
68
- design: { agent: "architect", mcp: "analyze" },
69
- review: { agent: "code-reviewer", mcp: "review" },
70
- document: { agent: "writer", mcp: "docs" },
71
- research: { agent: "scientist", mcp: "analyze" },
72
- "quick-fix": { agent: "build-fixer", mcp: "implement" },
73
- explain: { agent: "writer", mcp: "docs" },
74
- test: { agent: "test-engineer", mcp: null },
75
- };
76
-
77
- function routingFor(category) {
78
- const route = INTENT_CATEGORIES[category] || INTENT_CATEGORIES.implement;
79
- return {
80
- agent: route.agent,
81
- mcp: route.mcp,
82
- effort: resolveCodexAgentPolicy(route.agent).profile,
83
- };
84
- }
85
-
86
- /** @internal 키워드 → 카테고리 매핑 패턴 */
87
- const KEYWORD_PATTERNS = [
88
- {
89
- category: "implement",
90
- keywords: [
91
- "구현",
92
- "만들",
93
- "추가",
94
- "생성",
95
- "작성",
96
- "빌드",
97
- "implement",
98
- "create",
99
- "add",
100
- "build",
101
- "make",
102
- "develop",
103
- ],
104
- weight: 1.0,
105
- },
106
- {
107
- category: "debug",
108
- keywords: [
109
- "버그",
110
- "에러",
111
- "오류",
112
- "고쳐",
113
- "수정",
114
- "디버그",
115
- "fix",
116
- "bug",
117
- "error",
118
- "debug",
119
- "troubleshoot",
120
- "crash",
121
- "broken",
122
- ],
123
- weight: 1.0,
124
- },
125
- {
126
- category: "analyze",
127
- keywords: [
128
- "분석",
129
- "조사",
130
- "파악",
131
- "analyze",
132
- "investigate",
133
- "examine",
134
- "inspect",
135
- ],
136
- weight: 0.9,
137
- },
138
- {
139
- category: "design",
140
- keywords: [
141
- "설계",
142
- "아키텍처",
143
- "디자인",
144
- "구조",
145
- "design",
146
- "architect",
147
- "structure",
148
- ],
149
- weight: 0.9,
150
- },
151
- {
152
- category: "review",
153
- keywords: ["리뷰", "검토", "코드리뷰", "review", "code review", "audit"],
154
- weight: 1.0,
155
- },
156
- {
157
- category: "document",
158
- keywords: [
159
- "문서",
160
- "도큐먼트",
161
- "문서화",
162
- "document",
163
- "docs",
164
- "documentation",
165
- "readme",
166
- ],
167
- weight: 0.9,
168
- },
169
- {
170
- category: "research",
171
- keywords: ["리서치", "연구", "탐색", "research", "explore", "study"],
172
- weight: 0.8,
173
- },
174
- {
175
- category: "quick-fix",
176
- keywords: ["빠르게", "간단히", "급한", "quick fix", "hotfix", "quick"],
177
- weight: 0.85,
178
- },
179
- {
180
- category: "explain",
181
- keywords: [
182
- "설명",
183
- "뭐야",
184
- "알려",
185
- "이해",
186
- "explain",
187
- "what is",
188
- "how does",
189
- "tell me",
190
- "describe",
191
- ],
192
- weight: 1.0,
193
- },
194
- {
195
- category: "test",
196
- keywords: [
197
- "테스트",
198
- "테스팅",
199
- "시험",
200
- "검증",
201
- "test",
202
- "testing",
203
- "spec",
204
- "unit test",
205
- ],
206
- weight: 1.0,
207
- },
208
- ];
209
-
210
- /**
211
- * 키워드 기반 빠른 분류 (0-cost, Codex 호출 없이)
212
- * 고신뢰(>0.8) 시 Codex triage 건너뜀
213
- * @param {string} prompt - 사용자 프롬프트
214
- * @returns {{ category: string, confidence: number }}
215
- */
216
- export function quickClassify(prompt) {
217
- if (!prompt || typeof prompt !== "string" || !prompt.trim()) {
218
- return { category: "implement", confidence: 0.1 };
219
- }
220
-
221
- const lower = prompt.toLowerCase().trim();
222
- let bestCategory = null;
223
- let bestScore = 0;
224
- let bestMatchCount = 0;
225
-
226
- for (const { category, keywords, weight } of KEYWORD_PATTERNS) {
227
- let matchCount = 0;
228
- for (const kw of keywords) {
229
- if (lower.includes(kw)) matchCount++;
230
- }
231
- if (matchCount > 0) {
232
- const score = (matchCount / keywords.length) * weight;
233
- if (score > bestScore) {
234
- bestScore = score;
235
- bestCategory = category;
236
- bestMatchCount = matchCount;
237
- }
238
- }
239
- }
240
-
241
- if (!bestCategory) {
242
- return { category: "implement", confidence: 0.3 };
243
- }
244
-
245
- // 매칭 품질 기반 신뢰도 (0.5~0.95 범위) — matchCount 기준으로 정규화 (3개 매칭이면 최대)
246
- const confidence = Math.min(
247
- 0.95,
248
- 0.5 + (Math.min(bestMatchCount, 3) / 3) * 0.45,
249
- );
250
- return { category: bestCategory, confidence };
251
- }
252
-
253
- /**
254
- * 전체 의도 분류 — routing 정보 포함
255
- * Codex triage 경로: codex 설치 시 실행, confidence > 0.8이면 즉시 반환
256
- * quickClassify가 고신뢰(>0.8)이면 Codex 건너뜀
257
- * 결과는 md5 해시 기반 Map에 5분 TTL로 캐싱
258
- * @param {string} prompt
259
- * @returns {{ category: string, confidence: number, reasoning: string, routing: { agent: string, mcp: string|null, effort: string|null } }}
260
- */
261
- export function classifyIntent(prompt) {
262
- const hash = _promptHash(String(prompt ?? ""));
263
-
264
- // 캐시 확인
265
- const cached = _getCached(hash);
266
- if (cached) {
267
- const routing = routingFor(cached.category);
268
- return {
269
- category: cached.category,
270
- confidence: cached.confidence,
271
- reasoning: `cache-hit: ${cached.category} (${cached.confidence.toFixed(2)})`,
272
- routing,
273
- };
274
- }
275
-
276
- // quickClassify 먼저
277
- const quick = quickClassify(prompt);
278
-
279
- let category = quick.category;
280
- let confidence = quick.confidence;
281
- let reasoning;
282
-
283
- // quickClassify가 고신뢰(>0.8)이면 Codex 건너뜀
284
- if (quick.confidence > 0.8) {
285
- reasoning = `keyword-match: ${category} (${confidence.toFixed(2)})`;
286
- } else if (_isCodexAvailable()) {
287
- // Codex triage
288
- const codexResult = _tryCodexClassify(String(prompt ?? ""));
289
- if (codexResult && codexResult.confidence > 0.8) {
290
- category = codexResult.category;
291
- confidence = codexResult.confidence;
292
- reasoning = `codex-triage: ${category} (${confidence.toFixed(2)})`;
293
- } else {
294
- reasoning = `keyword-match(codex-fallback): ${category} (${confidence.toFixed(2)})`;
295
- }
296
- } else {
297
- reasoning = `keyword-match: ${category} (${confidence.toFixed(2)})`;
298
- }
299
-
300
- // 캐시 저장
301
- _intentCache.set(hash, { category, confidence, ts: Date.now() });
302
-
303
- const routing = routingFor(category);
304
- return {
305
- category,
306
- confidence,
307
- reasoning,
308
- routing,
309
- };
310
- }
311
-
312
- /**
313
- * 분류 히스토리 기반 학습 (reflexion 연동 가능)
314
- * @param {string} prompt
315
- * @param {string} actualCategory - 실제 카테고리
316
- */
317
- export function refineClassification(prompt, actualCategory) {
318
- // reflexion 연동 시 store에 오분류 기록 저장 예정
319
- void prompt;
320
- void actualCategory;
321
- }