@triflux/remote 10.0.1 → 10.25.1
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/pipe.mjs +239 -121
- package/hub/public/dashboard.html +68 -7
- package/hub/server.mjs +2181 -701
- package/hub/store-adapter.mjs +101 -37
- package/hub/store.mjs +356 -153
- package/hub/team/agent-map.json +26 -7
- package/hub/team/ansi.mjs +245 -146
- package/hub/team/backend.mjs +84 -17
- package/hub/team/build-worker-prompt.mjs +42 -0
- package/hub/team/check-mcp-hub.mjs +49 -0
- package/hub/team/claude-daemon-control.mjs +219 -0
- package/hub/team/claude-native-bridge.mjs +784 -0
- package/hub/team/claude-session-projection.mjs +65 -0
- package/hub/team/cli/commands/attach.mjs +57 -37
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +95 -74
- package/hub/team/cli/commands/focus.mjs +80 -53
- package/hub/team/cli/commands/interrupt.mjs +18 -6
- package/hub/team/cli/commands/kill.mjs +16 -5
- package/hub/team/cli/commands/list.mjs +31 -24
- package/hub/team/cli/commands/send.mjs +19 -6
- package/hub/team/cli/commands/start/index.mjs +154 -33
- package/hub/team/cli/commands/start/parse-args.mjs +89 -12
- package/hub/team/cli/commands/start/start-headless.mjs +127 -37
- package/hub/team/cli/commands/start/start-in-process.mjs +50 -40
- package/hub/team/cli/commands/start/start-mux.mjs +122 -73
- package/hub/team/cli/commands/start/start-wt.mjs +86 -69
- package/hub/team/cli/commands/status.mjs +43 -14
- package/hub/team/cli/commands/stop.mjs +11 -4
- package/hub/team/cli/commands/task.mjs +8 -3
- package/hub/team/cli/commands/tasks.mjs +13 -13
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +52 -30
- package/hub/team/cli/services/attach-fallback.mjs +74 -54
- package/hub/team/cli/services/hub-client.mjs +45 -17
- package/hub/team/cli/services/member-selector.mjs +37 -30
- package/hub/team/cli/services/native-control.mjs +144 -116
- package/hub/team/cli/services/runtime-mode.mjs +55 -1
- package/hub/team/cli/services/state-store.mjs +66 -9
- package/hub/team/cli/services/task-model.mjs +40 -30
- package/hub/team/codex-review.mjs +521 -0
- package/hub/team/conductor-mesh-bridge.mjs +25 -24
- package/hub/team/conductor-registry.mjs +121 -0
- package/hub/team/conductor.mjs +1379 -671
- package/hub/team/consensus-meta.mjs +176 -0
- package/hub/team/dashboard-anchor.mjs +4 -5
- package/hub/team/dashboard-layout.mjs +3 -1
- package/hub/team/dashboard-open.mjs +21 -119
- package/hub/team/dashboard.mjs +76 -28
- package/hub/team/event-log.mjs +18 -10
- package/hub/team/execution-mode.mjs +241 -0
- package/hub/team/extract-completion-payload.mjs +110 -0
- package/hub/team/git-preflight.mjs +286 -0
- package/hub/team/handoff.mjs +49 -18
- package/hub/team/headless-bridge-session.mjs +17 -0
- package/hub/team/headless.mjs +2065 -1156
- package/hub/team/health-probe.mjs +232 -69
- package/hub/team/launcher-template.mjs +23 -13
- package/hub/team/lead-control.mjs +91 -4
- package/hub/team/mcp-selector.mjs +145 -0
- package/hub/team/native-supervisor.mjs +90 -26
- package/hub/team/native.mjs +74 -35
- package/hub/team/nativeProxy.mjs +184 -113
- package/hub/team/notify.mjs +147 -78
- package/hub/team/orchestrator.mjs +173 -161
- package/hub/team/pane.mjs +43 -15
- package/hub/team/process-cleanup.mjs +69 -25
- package/hub/team/psmux.mjs +1067 -264
- package/hub/team/recovery-store.mjs +149 -0
- package/hub/team/remote-probe.mjs +69 -53
- package/hub/team/remote-session.mjs +131 -59
- package/hub/team/remote-watcher.mjs +62 -34
- package/hub/team/retry-state-machine.mjs +267 -0
- package/hub/team/routing.mjs +51 -25
- package/hub/team/runtime-strategy.mjs +200 -0
- package/hub/team/schemas/worker-completion.json +39 -0
- package/hub/team/sentinel-capture.mjs +127 -0
- package/hub/team/session-sync.mjs +153 -6
- package/hub/team/session.mjs +605 -611
- package/hub/team/shared.mjs +13 -13
- package/hub/team/staleState.mjs +72 -30
- package/hub/team/swarm-cli.mjs +390 -0
- package/hub/team/swarm-hypervisor.mjs +1526 -198
- package/hub/team/swarm-intent.mjs +216 -0
- package/hub/team/swarm-locks.mjs +140 -25
- package/hub/team/swarm-planner.mjs +121 -21
- package/hub/team/swarm-preflight.mjs +317 -0
- package/hub/team/swarm-reconciler.mjs +128 -23
- package/hub/team/synapse-cli.mjs +458 -0
- package/hub/team/synapse-http.mjs +60 -0
- package/hub/team/synapse-registry.mjs +329 -0
- package/hub/team/terminal-opener.mjs +216 -0
- package/hub/team/tui-core.mjs +288 -0
- package/hub/team/tui-lite.mjs +234 -146
- package/hub/team/tui-remote-adapter.mjs +21 -37
- package/hub/team/tui-synapse.mjs +223 -0
- package/hub/team/tui-viewer.mjs +104 -45
- package/hub/team/tui-widgets.mjs +262 -0
- package/hub/team/tui.mjs +936 -449
- package/hub/team/worker-completion-validator.mjs +84 -0
- package/hub/team/worker-sandbox.mjs +93 -0
- package/hub/team/worker-signal.mjs +263 -0
- package/hub/team/worker-signal.types.d.ts +52 -0
- package/hub/team/worktree-lifecycle.mjs +518 -64
- package/hub/team/wt-manager.mjs +297 -26
- package/hub/tools.mjs +474 -252
- package/hub/tray.mjs +411 -368
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-app-server-worker.mjs +1015 -0
- package/hub/workers/codex-mcp.mjs +724 -507
- package/hub/workers/delegator-mcp.mjs +663 -337
- package/hub/workers/factory.mjs +100 -21
- package/hub/workers/gemini-worker.mjs +179 -86
- package/hub/workers/interface.mjs +23 -2
- package/hub/workers/lib/jsonrpc-stdio.mjs +463 -0
- package/hub/workers/worker-utils.mjs +22 -16
- package/package.json +4 -3
- package/scripts/lib/agent-json.mjs +27 -0
- package/scripts/lib/async.mjs +174 -0
- package/scripts/lib/claudemd-scanner.mjs +223 -0
- 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 +67 -0
- package/scripts/lib/codex-recovery.sh +50 -0
- package/scripts/lib/context.mjs +67 -0
- package/scripts/lib/cross-review-utils.mjs +59 -0
- package/scripts/lib/doctor-env-checks.mjs +121 -0
- package/scripts/lib/dynamic-route-cli.mjs +107 -0
- package/scripts/lib/env-probe.mjs +269 -0
- package/scripts/lib/env.mjs +14 -0
- package/scripts/lib/gemini-profiles.mjs +119 -0
- package/scripts/lib/handoff.mjs +187 -0
- package/scripts/lib/hook-utils.mjs +16 -0
- package/scripts/lib/hub.mjs +48 -0
- package/scripts/lib/keyword-rules.mjs +195 -0
- package/scripts/lib/logger.mjs +105 -0
- package/scripts/lib/mcp-filter.mjs +883 -0
- package/scripts/lib/mcp-gateway-servers.mjs +70 -0
- package/scripts/lib/mcp-guard-engine.mjs +2120 -0
- package/scripts/lib/mcp-health.mjs +773 -0
- package/scripts/lib/mcp-manifest.mjs +89 -0
- package/scripts/lib/mcp-server-catalog.mjs +355 -0
- package/scripts/lib/pid.mjs +63 -0
- package/scripts/lib/process-utils.mjs +26 -0
- package/scripts/lib/psmux-info.mjs +179 -0
- package/scripts/lib/quota.mjs +47 -0
- package/scripts/lib/remote-spawn-transfer.mjs +226 -0
- package/scripts/lib/skill-state.mjs +220 -0
- package/scripts/lib/skill-template.mjs +375 -0
- 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
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
const VALID_MCP_ROUTES = new Set(["codex", "gemini", "claude"]);
|
|
4
|
+
|
|
5
|
+
function logRuleError(message, error) {
|
|
6
|
+
if (error) {
|
|
7
|
+
console.error(`[triflux-keyword-rules] ${message}: ${error.message}`);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
console.error(`[triflux-keyword-rules] ${message}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function normalizePattern(pattern) {
|
|
14
|
+
if (!pattern || typeof pattern.source !== "string") return null;
|
|
15
|
+
if (typeof pattern.flags !== "string") return null;
|
|
16
|
+
return { source: pattern.source, flags: pattern.flags };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeState(state) {
|
|
20
|
+
if (state == null) return null;
|
|
21
|
+
if (typeof state !== "object") return null;
|
|
22
|
+
if (typeof state.activate !== "boolean") return null;
|
|
23
|
+
if (typeof state.name !== "string" || !state.name.trim()) return null;
|
|
24
|
+
return { activate: state.activate, name: state.name.trim() };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeRule(rule) {
|
|
28
|
+
if (!rule || typeof rule !== "object") return null;
|
|
29
|
+
if (typeof rule.id !== "string" || !rule.id.trim()) return null;
|
|
30
|
+
if (!Array.isArray(rule.patterns) || rule.patterns.length === 0) return null;
|
|
31
|
+
if (typeof rule.priority !== "number" || !Number.isFinite(rule.priority))
|
|
32
|
+
return null;
|
|
33
|
+
|
|
34
|
+
const patterns = rule.patterns.map(normalizePattern).filter(Boolean);
|
|
35
|
+
if (patterns.length === 0) return null;
|
|
36
|
+
|
|
37
|
+
const skill =
|
|
38
|
+
typeof rule.skill === "string" && rule.skill.trim()
|
|
39
|
+
? rule.skill.trim()
|
|
40
|
+
: null;
|
|
41
|
+
const action =
|
|
42
|
+
typeof rule.action === "string" && rule.action.trim()
|
|
43
|
+
? rule.action.trim()
|
|
44
|
+
: null;
|
|
45
|
+
const mcpRoute =
|
|
46
|
+
typeof rule.mcp_route === "string" && VALID_MCP_ROUTES.has(rule.mcp_route)
|
|
47
|
+
? rule.mcp_route
|
|
48
|
+
: null;
|
|
49
|
+
|
|
50
|
+
if (!skill && !mcpRoute && !action) return null;
|
|
51
|
+
|
|
52
|
+
const hint =
|
|
53
|
+
typeof rule.hint === "string" && rule.hint.trim() ? rule.hint.trim() : null;
|
|
54
|
+
|
|
55
|
+
const supersedes = Array.isArray(rule.supersedes)
|
|
56
|
+
? rule.supersedes
|
|
57
|
+
.filter((id) => typeof id === "string" && id.trim())
|
|
58
|
+
.map((id) => id.trim())
|
|
59
|
+
: [];
|
|
60
|
+
|
|
61
|
+
const state = normalizeState(rule.state);
|
|
62
|
+
if (rule.state != null && state == null) return null;
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
id: rule.id.trim(),
|
|
66
|
+
patterns,
|
|
67
|
+
skill,
|
|
68
|
+
action,
|
|
69
|
+
hint,
|
|
70
|
+
priority: rule.priority,
|
|
71
|
+
supersedes,
|
|
72
|
+
exclusive: rule.exclusive === true,
|
|
73
|
+
state,
|
|
74
|
+
mcp_route: mcpRoute,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 외부 JSON 규칙 로드 + 스키마 검증
|
|
79
|
+
export function loadRules(rulesPath) {
|
|
80
|
+
try {
|
|
81
|
+
const raw = readFileSync(rulesPath, "utf8");
|
|
82
|
+
const parsed = JSON.parse(raw);
|
|
83
|
+
if (!parsed || !Array.isArray(parsed.rules)) {
|
|
84
|
+
logRuleError(`규칙 형식이 올바르지 않습니다: ${rulesPath}`);
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const normalized = parsed.rules.map(normalizeRule).filter(Boolean);
|
|
89
|
+
return normalized;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logRuleError(`규칙 파일을 읽을 수 없습니다: ${rulesPath}`, error);
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// pattern.source / flags를 RegExp로 컴파일
|
|
97
|
+
export function compileRules(rules) {
|
|
98
|
+
return rules
|
|
99
|
+
.map((rule) => {
|
|
100
|
+
try {
|
|
101
|
+
return {
|
|
102
|
+
...rule,
|
|
103
|
+
compiledPatterns: rule.patterns.map(
|
|
104
|
+
(p) => new RegExp(p.source, p.flags),
|
|
105
|
+
),
|
|
106
|
+
};
|
|
107
|
+
} catch (error) {
|
|
108
|
+
logRuleError(`정규식 컴파일 실패: ${rule.id}`, error);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
.filter(Boolean);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 입력 텍스트에서 매칭된 규칙 목록 반환
|
|
116
|
+
export function matchRules(compiledRules, cleanText) {
|
|
117
|
+
if (
|
|
118
|
+
!Array.isArray(compiledRules) ||
|
|
119
|
+
typeof cleanText !== "string" ||
|
|
120
|
+
!cleanText
|
|
121
|
+
) {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const matches = [];
|
|
126
|
+
|
|
127
|
+
for (const rule of compiledRules) {
|
|
128
|
+
if (
|
|
129
|
+
!Array.isArray(rule.compiledPatterns) ||
|
|
130
|
+
rule.compiledPatterns.length === 0
|
|
131
|
+
) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const matched = rule.compiledPatterns.some((pattern) => {
|
|
136
|
+
pattern.lastIndex = 0;
|
|
137
|
+
return pattern.test(cleanText);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!matched) continue;
|
|
141
|
+
|
|
142
|
+
matches.push({
|
|
143
|
+
id: rule.id,
|
|
144
|
+
skill: rule.skill,
|
|
145
|
+
action: rule.action,
|
|
146
|
+
hint: rule.hint || null,
|
|
147
|
+
priority: rule.priority,
|
|
148
|
+
supersedes: rule.supersedes || [],
|
|
149
|
+
exclusive: rule.exclusive === true,
|
|
150
|
+
state: rule.state || null,
|
|
151
|
+
mcp_route: rule.mcp_route || null,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return matches;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// priority 정렬 + supersedes + exclusive 처리
|
|
159
|
+
export function resolveConflicts(matches) {
|
|
160
|
+
try {
|
|
161
|
+
if (!Array.isArray(matches) || matches.length === 0) return [];
|
|
162
|
+
|
|
163
|
+
const sorted = [...matches].sort((a, b) => {
|
|
164
|
+
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
165
|
+
return String(a.id).localeCompare(String(b.id));
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const deduped = [];
|
|
169
|
+
const seen = new Set();
|
|
170
|
+
for (const match of sorted) {
|
|
171
|
+
if (seen.has(match.id)) continue;
|
|
172
|
+
deduped.push(match);
|
|
173
|
+
seen.add(match.id);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const superseded = new Set();
|
|
177
|
+
const resolved = [];
|
|
178
|
+
|
|
179
|
+
for (const match of deduped) {
|
|
180
|
+
if (superseded.has(match.id)) continue;
|
|
181
|
+
resolved.push(match);
|
|
182
|
+
for (const targetId of match.supersedes || []) {
|
|
183
|
+
superseded.add(targetId);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const exclusiveMatch = resolved.find((match) => match.exclusive === true);
|
|
188
|
+
if (exclusiveMatch) return [exclusiveMatch];
|
|
189
|
+
|
|
190
|
+
return resolved;
|
|
191
|
+
} catch (error) {
|
|
192
|
+
logRuleError("규칙 충돌 해결 실패", error);
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logify — triflux 구조화 로깅 설정
|
|
3
|
+
*
|
|
4
|
+
* 사용법:
|
|
5
|
+
* import { logger, createModuleLogger } from './lib/logger.mjs';
|
|
6
|
+
*
|
|
7
|
+
* // 기본 로거
|
|
8
|
+
* logger.info({ taskId: 'abc' }, 'task.started');
|
|
9
|
+
*
|
|
10
|
+
* // 모듈별 로거
|
|
11
|
+
* const log = createModuleLogger('hub');
|
|
12
|
+
* log.info({ port: 27888 }, 'server.started');
|
|
13
|
+
* log.error({ err }, 'server.error');
|
|
14
|
+
*
|
|
15
|
+
* 이벤트 네이밍: {도메인}.{액션} 형식
|
|
16
|
+
* hub.started, hub.stopped, route.started, route.completed,
|
|
17
|
+
* worker.spawned, worker.completed, worker.timeout,
|
|
18
|
+
* mcp.connected, mcp.disconnected, mcp.error,
|
|
19
|
+
* team.created, team.deleted, task.claimed, task.completed,
|
|
20
|
+
* pipe.connected, pipe.message, pipe.error,
|
|
21
|
+
* http.request, http.response, http.error
|
|
22
|
+
*
|
|
23
|
+
* 로그 레벨 가이드:
|
|
24
|
+
* debug — 개발/트러블슈팅용 (변수 값, MCP 메시지, 캐시 키)
|
|
25
|
+
* info — 정상 흐름 상태 변경 (서버 시작, 워커 완료, 팀 생성)
|
|
26
|
+
* warn — 위험 신호 (재시도 발생, 쿼타 임박, 느린 워커)
|
|
27
|
+
* error — 작업 실패 (CLI 실행 실패, MCP 연결 끊김)
|
|
28
|
+
* fatal — 프로세스 위협 (DB 연결 불가, 포트 충돌)
|
|
29
|
+
*/
|
|
30
|
+
import pino from "pino";
|
|
31
|
+
|
|
32
|
+
const isDev = process.env.NODE_ENV !== "production";
|
|
33
|
+
|
|
34
|
+
export const logger = pino({
|
|
35
|
+
level: process.env.LOG_LEVEL || (isDev ? "debug" : "info"),
|
|
36
|
+
|
|
37
|
+
// 모든 로그에 포함되는 기본 필드
|
|
38
|
+
base: {
|
|
39
|
+
service: process.env.SERVICE_NAME || "triflux",
|
|
40
|
+
env: process.env.NODE_ENV || "development",
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// 레벨을 대문자로 출력 (AI 파싱 용이)
|
|
44
|
+
formatters: {
|
|
45
|
+
level: (label) => ({ level: label.toUpperCase() }),
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// ISO 8601 타임스탬프
|
|
49
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
50
|
+
|
|
51
|
+
// 민감정보 자동 필터링
|
|
52
|
+
redact: {
|
|
53
|
+
paths: [
|
|
54
|
+
"password",
|
|
55
|
+
"token",
|
|
56
|
+
"apiKey",
|
|
57
|
+
"secret",
|
|
58
|
+
"authorization",
|
|
59
|
+
"*.password",
|
|
60
|
+
"*.token",
|
|
61
|
+
"*.apiKey",
|
|
62
|
+
"*.secret",
|
|
63
|
+
"req.headers.authorization",
|
|
64
|
+
"req.headers.cookie",
|
|
65
|
+
"hubToken",
|
|
66
|
+
],
|
|
67
|
+
remove: true,
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// 개발 환경: 컬러 콘솔 출력
|
|
71
|
+
transport: isDev
|
|
72
|
+
? {
|
|
73
|
+
target: "pino-pretty",
|
|
74
|
+
options: {
|
|
75
|
+
colorize: true,
|
|
76
|
+
translateTime: "yyyy-mm-dd HH:MM:ss",
|
|
77
|
+
ignore: "pid,hostname",
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: undefined,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 모듈별 Child Logger 생성.
|
|
85
|
+
* 모듈 이름이 모든 로그에 자동 포함된다.
|
|
86
|
+
*
|
|
87
|
+
* @param {string} module — 모듈 이름 (hub, route, worker, mcp, team 등)
|
|
88
|
+
* @returns {import('pino').Logger}
|
|
89
|
+
*/
|
|
90
|
+
export function createModuleLogger(module) {
|
|
91
|
+
return logger.child({ module });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 정상 종료 시 버퍼 flush 보장
|
|
95
|
+
process.on("uncaughtException", (err) => {
|
|
96
|
+
logger.fatal({ err }, "process.uncaught_exception");
|
|
97
|
+
logger.flush();
|
|
98
|
+
process.exit(1);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
process.on("unhandledRejection", (reason) => {
|
|
102
|
+
logger.fatal({ reason: String(reason) }, "process.unhandled_rejection");
|
|
103
|
+
logger.flush();
|
|
104
|
+
process.exit(1);
|
|
105
|
+
});
|