@triflux/remote 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.
Files changed (162) hide show
  1. package/hub/pipe.mjs +239 -121
  2. package/hub/public/dashboard.html +61 -0
  3. package/hub/server.mjs +2179 -709
  4. package/hub/store-adapter.mjs +59 -26
  5. package/hub/store.mjs +356 -153
  6. package/hub/team/agent-map.json +26 -7
  7. package/hub/team/ansi.mjs +245 -146
  8. package/hub/team/backend.mjs +78 -17
  9. package/hub/team/build-worker-prompt.mjs +73 -0
  10. package/hub/team/check-mcp-hub.mjs +49 -0
  11. package/hub/team/claude-daemon-control.mjs +1130 -0
  12. package/hub/team/claude-native-bridge.mjs +1011 -0
  13. package/hub/team/claude-session-projection.mjs +74 -0
  14. package/hub/team/cli/commands/attach.mjs +57 -37
  15. package/hub/team/cli/commands/control.mjs +29 -8
  16. package/hub/team/cli/commands/debug.mjs +95 -74
  17. package/hub/team/cli/commands/focus.mjs +80 -53
  18. package/hub/team/cli/commands/interrupt.mjs +18 -6
  19. package/hub/team/cli/commands/kill.mjs +16 -5
  20. package/hub/team/cli/commands/list.mjs +31 -24
  21. package/hub/team/cli/commands/send.mjs +19 -6
  22. package/hub/team/cli/commands/start/index.mjs +151 -33
  23. package/hub/team/cli/commands/start/parse-args.mjs +97 -13
  24. package/hub/team/cli/commands/start/start-headless.mjs +155 -37
  25. package/hub/team/cli/commands/start/start-in-process.mjs +50 -40
  26. package/hub/team/cli/commands/start/start-mux.mjs +122 -73
  27. package/hub/team/cli/commands/start/start-wt.mjs +86 -69
  28. package/hub/team/cli/commands/status.mjs +43 -14
  29. package/hub/team/cli/commands/stop.mjs +11 -4
  30. package/hub/team/cli/commands/task.mjs +8 -3
  31. package/hub/team/cli/commands/tasks.mjs +13 -13
  32. package/hub/team/cli/help.mjs +1 -1
  33. package/hub/team/cli/index.mjs +2 -2
  34. package/hub/team/cli/manifest.mjs +38 -8
  35. package/hub/team/cli/render.mjs +52 -30
  36. package/hub/team/cli/services/attach-fallback.mjs +74 -54
  37. package/hub/team/cli/services/hub-client.mjs +44 -16
  38. package/hub/team/cli/services/member-selector.mjs +37 -30
  39. package/hub/team/cli/services/native-control.mjs +144 -116
  40. package/hub/team/cli/services/runtime-mode.mjs +61 -4
  41. package/hub/team/cli/services/state-store.mjs +66 -9
  42. package/hub/team/cli/services/task-model.mjs +40 -30
  43. package/hub/team/codex-review.mjs +521 -0
  44. package/hub/team/conductor-mesh-bridge.mjs +25 -24
  45. package/hub/team/conductor-registry.mjs +121 -0
  46. package/hub/team/conductor.mjs +1379 -671
  47. package/hub/team/consensus-meta.mjs +176 -0
  48. package/hub/team/dashboard-anchor.mjs +4 -5
  49. package/hub/team/dashboard-layout.mjs +3 -1
  50. package/hub/team/dashboard-open.mjs +20 -118
  51. package/hub/team/dashboard.mjs +76 -28
  52. package/hub/team/event-log.mjs +18 -10
  53. package/hub/team/execution-mode.mjs +256 -0
  54. package/hub/team/extract-completion-payload.mjs +110 -0
  55. package/hub/team/git-preflight.mjs +286 -0
  56. package/hub/team/handoff.mjs +49 -18
  57. package/hub/team/headless-bridge-session.mjs +17 -0
  58. package/hub/team/headless.mjs +2213 -1156
  59. package/hub/team/health-probe.mjs +232 -69
  60. package/hub/team/interactive-native-launcher.mjs +106 -0
  61. package/hub/team/interactive-native-worker.mjs +80 -0
  62. package/hub/team/interactive-tui-transport.mjs +465 -0
  63. package/hub/team/launcher-template.mjs +49 -17
  64. package/hub/team/lead-control.mjs +91 -4
  65. package/hub/team/mcp-selector.mjs +145 -0
  66. package/hub/team/native-supervisor.mjs +90 -26
  67. package/hub/team/native.mjs +120 -42
  68. package/hub/team/nativeProxy.mjs +184 -113
  69. package/hub/team/notify.mjs +147 -78
  70. package/hub/team/orchestrator.mjs +173 -161
  71. package/hub/team/pane.mjs +43 -20
  72. package/hub/team/process-cleanup.mjs +69 -25
  73. package/hub/team/psmux.mjs +1022 -281
  74. package/hub/team/recovery-store.mjs +149 -0
  75. package/hub/team/remote-probe.mjs +68 -52
  76. package/hub/team/remote-session.mjs +131 -59
  77. package/hub/team/remote-watcher.mjs +61 -33
  78. package/hub/team/retry-state-machine.mjs +336 -0
  79. package/hub/team/routing.mjs +51 -25
  80. package/hub/team/runtime-strategy.mjs +200 -0
  81. package/hub/team/schemas/worker-completion.json +39 -0
  82. package/hub/team/sentinel-capture.mjs +127 -0
  83. package/hub/team/session-sync.mjs +153 -6
  84. package/hub/team/session.mjs +574 -611
  85. package/hub/team/shared.mjs +13 -13
  86. package/hub/team/staleState.mjs +72 -30
  87. package/hub/team/swarm-cli.mjs +390 -0
  88. package/hub/team/swarm-hypervisor.mjs +1544 -193
  89. package/hub/team/swarm-intent.mjs +216 -0
  90. package/hub/team/swarm-locks.mjs +140 -25
  91. package/hub/team/swarm-planner.mjs +121 -21
  92. package/hub/team/swarm-preflight.mjs +319 -0
  93. package/hub/team/swarm-reconciler.mjs +128 -23
  94. package/hub/team/synapse-cli.mjs +458 -0
  95. package/hub/team/synapse-http.mjs +60 -0
  96. package/hub/team/synapse-registry.mjs +329 -0
  97. package/hub/team/terminal-opener.mjs +216 -0
  98. package/hub/team/tui-core.mjs +292 -0
  99. package/hub/team/tui-lite.mjs +237 -148
  100. package/hub/team/tui-remote-adapter.mjs +18 -34
  101. package/hub/team/tui-synapse.mjs +223 -0
  102. package/hub/team/tui-viewer.mjs +108 -48
  103. package/hub/team/tui-widgets.mjs +262 -0
  104. package/hub/team/tui.mjs +931 -439
  105. package/hub/team/worker-completion-validator.mjs +84 -0
  106. package/hub/team/worker-sandbox.mjs +97 -0
  107. package/hub/team/worker-signal.mjs +263 -0
  108. package/hub/team/worker-signal.types.d.ts +52 -0
  109. package/hub/team/worktree-lifecycle.mjs +517 -63
  110. package/hub/team/wt-manager.mjs +297 -26
  111. package/hub/tools.mjs +477 -252
  112. package/hub/tray.mjs +411 -368
  113. package/hub/workers/antigravity-route-worker.mjs +169 -0
  114. package/hub/workers/claude-worker.mjs +162 -118
  115. package/hub/workers/codex-app-server-worker.mjs +1015 -0
  116. package/hub/workers/codex-mcp.mjs +724 -507
  117. package/hub/workers/delegator-mcp.mjs +570 -499
  118. package/hub/workers/factory.mjs +103 -21
  119. package/hub/workers/gemini-worker.mjs +126 -284
  120. package/hub/workers/interface.mjs +24 -2
  121. package/hub/workers/lib/jsonrpc-stdio.mjs +463 -0
  122. package/hub/workers/worker-utils.mjs +23 -17
  123. package/package.json +4 -3
  124. package/scripts/lib/agent-json.mjs +27 -0
  125. package/scripts/lib/async.mjs +174 -0
  126. package/scripts/lib/claudemd-scanner.mjs +223 -0
  127. package/scripts/lib/cli-agy.mjs +62 -0
  128. package/scripts/lib/cli-claude.mjs +78 -0
  129. package/scripts/lib/cli-codex.mjs +199 -0
  130. package/scripts/lib/cli-gemini.mjs +37 -0
  131. package/scripts/lib/codex-recovery.sh +50 -0
  132. package/scripts/lib/context.mjs +67 -0
  133. package/scripts/lib/cross-review-utils.mjs +59 -0
  134. package/scripts/lib/doctor-env-checks.mjs +121 -0
  135. package/scripts/lib/dynamic-route-cli.mjs +107 -0
  136. package/scripts/lib/env-probe.mjs +269 -0
  137. package/scripts/lib/env.mjs +14 -0
  138. package/scripts/lib/gemini-profiles.mjs +119 -0
  139. package/scripts/lib/handoff.mjs +187 -0
  140. package/scripts/lib/hook-utils.mjs +16 -0
  141. package/scripts/lib/hub.mjs +48 -0
  142. package/scripts/lib/keyword-rules.mjs +195 -0
  143. package/scripts/lib/logger.mjs +105 -0
  144. package/scripts/lib/mcp-filter.mjs +883 -0
  145. package/scripts/lib/mcp-gateway-health-check.mjs +159 -0
  146. package/scripts/lib/mcp-gateway-servers.mjs +70 -0
  147. package/scripts/lib/mcp-gateway-wrapper-check.mjs +35 -0
  148. package/scripts/lib/mcp-guard-engine.mjs +2120 -0
  149. package/scripts/lib/mcp-health.mjs +773 -0
  150. package/scripts/lib/mcp-manifest.mjs +89 -0
  151. package/scripts/lib/mcp-server-catalog.mjs +355 -0
  152. package/scripts/lib/pid.mjs +63 -0
  153. package/scripts/lib/process-utils.mjs +26 -0
  154. package/scripts/lib/psmux-info.mjs +224 -0
  155. package/scripts/lib/quota.mjs +47 -0
  156. package/scripts/lib/remote-spawn-transfer.mjs +226 -0
  157. package/scripts/lib/skill-state.mjs +220 -0
  158. package/scripts/lib/skill-template.mjs +375 -0
  159. package/scripts/lib/team.mjs +75 -0
  160. package/scripts/lib/timeout.mjs +66 -0
  161. package/scripts/lib/tmp.mjs +26 -0
  162. 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", "antigravity", "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
+ });