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