@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,292 @@
1
+ // hub/team/tui-core.mjs — 대시보드 공통 유틸리티 (ISSUE-11)
2
+ // tui.mjs / tui-lite.mjs 간 중복 로직을 단일 모듈로 통합.
3
+
4
+ import { FG, MOCHA, wcswidth } from "./ansi.mjs";
5
+
6
+ // ── 상수 ──────────────────────────────────────────────────────────────────
7
+ export const FALLBACK_COLUMNS = 100;
8
+ export const FALLBACK_ROWS = 30;
9
+ export const VALID_TABS = Object.freeze(["log", "detail", "files"]);
10
+
11
+ // ── 버전 로드 ─────────────────────────────────────────────────────────────
12
+ let _cachedVersion = null;
13
+ export async function loadVersion(fallback = "7.x") {
14
+ if (_cachedVersion) return _cachedVersion;
15
+ try {
16
+ const { createRequire } = await import("node:module");
17
+ const require = createRequire(import.meta.url);
18
+ _cachedVersion = require("../../package.json").version;
19
+ } catch {
20
+ _cachedVersion = fallback;
21
+ }
22
+ return _cachedVersion;
23
+ }
24
+
25
+ // ── 수학 유틸 ─────────────────────────────────────────────────────────────
26
+ export function clamp(value, min, max) {
27
+ return Math.min(max, Math.max(min, value));
28
+ }
29
+
30
+ // ── 텍스트 정규화 ─────────────────────────────────────────────────────────
31
+ export function stripCodeBlocks(text) {
32
+ return String(text || "")
33
+ .replace(/\r/g, "")
34
+ .replace(/```[\s\S]*?(?:```|$)/g, "\n")
35
+ .replace(/^\s*```.*$/gm, "")
36
+ .replace(/^(?: {4}|\t).+$/gm, "")
37
+ .replace(/^(?:PS\s+\S[^\n]*?>|>\s+|\$\s+)[^\n]*/gm, "")
38
+ .trim();
39
+ }
40
+
41
+ export function sanitizeTextBlock(text, rawMode = false) {
42
+ const normalized = rawMode
43
+ ? String(text || "").replace(/\r/g, "")
44
+ : stripCodeBlocks(text);
45
+ return normalized
46
+ .split("\n")
47
+ .map((line) => line.trim())
48
+ .filter(Boolean)
49
+ .filter((line) => line !== "--- HANDOFF ---")
50
+ .join("\n")
51
+ .trim();
52
+ }
53
+
54
+ export function sanitizeOneLine(text, fallback = "") {
55
+ return sanitizeTextBlock(text).replace(/\s+/g, " ").trim() || fallback;
56
+ }
57
+
58
+ export function sanitizeFiles(files) {
59
+ if (!files) return [];
60
+ const raw = Array.isArray(files) ? files : String(files).split(",");
61
+ return raw.map((e) => sanitizeOneLine(e)).filter(Boolean);
62
+ }
63
+
64
+ export function sanitizeFindings(findings) {
65
+ if (!findings) return [];
66
+ const raw = Array.isArray(findings)
67
+ ? findings
68
+ : sanitizeTextBlock(findings).split("\n");
69
+ return raw.map((e) => sanitizeOneLine(e)).filter(Boolean);
70
+ }
71
+
72
+ export function normalizeTokens(tokens) {
73
+ if (tokens === null || tokens === undefined || tokens === "") return "";
74
+ if (typeof tokens === "number" && Number.isFinite(tokens)) return tokens;
75
+ const raw = sanitizeOneLine(tokens);
76
+ if (!raw) return "";
77
+ const match = raw.match(/(\d+(?:[.,]\d+)?\s*[kKmM]?)/);
78
+ return match ? match[1].replace(/\s+/g, "").toLowerCase() : raw;
79
+ }
80
+
81
+ export function formatTokens(tokens) {
82
+ if (tokens === null || tokens === undefined || tokens === "") return "n/a";
83
+ if (typeof tokens === "number" && Number.isFinite(tokens)) {
84
+ if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}m`;
85
+ if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}k`;
86
+ return `${tokens}`;
87
+ }
88
+ return String(tokens);
89
+ }
90
+
91
+ // ── 워커 상태 ─────────────────────────────────────────────────────────────
92
+ export function runtimeStatus(worker) {
93
+ return worker?.handoff?.status || worker?.status || "pending";
94
+ }
95
+
96
+ /**
97
+ * 워커 상태 정규화 (tui.mjs / tui-lite.mjs 공통)
98
+ * @param {object} existing - 기존 워커 상태
99
+ * @param {object} state - 새 상태 패치
100
+ * @param {object} [opts]
101
+ * @param {boolean} [opts.trackChanges=false] - _prevStatus/_statusChangedAt 추적 (full TUI용)
102
+ * @param {function} [opts.now=Date.now] - 시간 함수
103
+ */
104
+ export function normalizeWorkerState(existing = {}, state = {}, opts = {}) {
105
+ const { trackChanges = false, now = Date.now } = opts;
106
+
107
+ const nextHandoff =
108
+ state.handoff === undefined
109
+ ? existing.handoff
110
+ : {
111
+ ...(existing.handoff || {}),
112
+ ...(state.handoff || {}),
113
+ verdict:
114
+ state.handoff?.verdict !== undefined
115
+ ? sanitizeOneLine(state.handoff.verdict)
116
+ : existing.handoff?.verdict,
117
+ confidence:
118
+ state.handoff?.confidence !== undefined
119
+ ? sanitizeOneLine(state.handoff.confidence)
120
+ : existing.handoff?.confidence,
121
+ status:
122
+ state.handoff?.status !== undefined
123
+ ? sanitizeOneLine(state.handoff.status)
124
+ : existing.handoff?.status,
125
+ files_changed:
126
+ state.handoff?.files_changed !== undefined
127
+ ? sanitizeFiles(state.handoff.files_changed)
128
+ : existing.handoff?.files_changed,
129
+ };
130
+
131
+ const merged = {
132
+ ...existing,
133
+ ...state,
134
+ cli:
135
+ state.cli !== undefined
136
+ ? sanitizeOneLine(state.cli, existing.cli || "codex")
137
+ : existing.cli || "codex",
138
+ role:
139
+ state.role !== undefined ? sanitizeOneLine(state.role) : existing.role,
140
+ displayName:
141
+ state.displayName !== undefined
142
+ ? sanitizeOneLine(state.displayName, existing.displayName)
143
+ : existing.displayName,
144
+ status:
145
+ state.status !== undefined
146
+ ? sanitizeOneLine(state.status, existing.status || "pending")
147
+ : existing.status || "pending",
148
+ snapshot:
149
+ state.snapshot !== undefined
150
+ ? sanitizeTextBlock(state.snapshot)
151
+ : existing.snapshot,
152
+ summary:
153
+ state.summary !== undefined
154
+ ? sanitizeTextBlock(state.summary)
155
+ : existing.summary,
156
+ detail:
157
+ state.detail !== undefined
158
+ ? sanitizeTextBlock(state.detail)
159
+ : existing.detail,
160
+ findings:
161
+ state.findings !== undefined
162
+ ? sanitizeFindings(state.findings)
163
+ : existing.findings,
164
+ files_changed:
165
+ state.files_changed !== undefined
166
+ ? sanitizeFiles(state.files_changed)
167
+ : existing.files_changed,
168
+ confidence:
169
+ state.confidence !== undefined
170
+ ? sanitizeOneLine(state.confidence)
171
+ : existing.confidence,
172
+ tokens:
173
+ state.tokens !== undefined
174
+ ? normalizeTokens(state.tokens)
175
+ : existing.tokens,
176
+ progress:
177
+ state.progress !== undefined
178
+ ? clamp(Number(state.progress) || 0, 0, 1)
179
+ : existing.progress,
180
+ handoff: nextHandoff,
181
+ };
182
+
183
+ if (trackChanges) {
184
+ const statusChanged =
185
+ state.status !== undefined &&
186
+ sanitizeOneLine(state.status) !== existing.status;
187
+ merged._prevStatus = statusChanged ? existing.status : existing._prevStatus;
188
+ merged._statusChangedAt = statusChanged
189
+ ? now()
190
+ : existing._statusChangedAt || 0;
191
+ }
192
+
193
+ return merged;
194
+ }
195
+
196
+ // ── 색상 헬퍼 ─────────────────────────────────────────────────────────────
197
+ export function cliColor(cli) {
198
+ if (cli === "gemini") return FG.gemini;
199
+ if (cli === "claude") return FG.claude;
200
+ if (cli === "codex") return FG.codex;
201
+ return FG.white;
202
+ }
203
+
204
+ export function statusColor(status) {
205
+ if (status === "ok" || status === "completed") return MOCHA.ok;
206
+ if (status === "partial") return MOCHA.partial;
207
+ if (status === "failed") return MOCHA.fail;
208
+ if (status === "running" || status === "in_progress") return MOCHA.executing;
209
+ return FG.muted;
210
+ }
211
+
212
+ export function countStatuses(names, workers) {
213
+ let ok = 0,
214
+ partial = 0,
215
+ failed = 0,
216
+ running = 0;
217
+ for (const name of names) {
218
+ const st = workers.get(name);
219
+ const s = runtimeStatus(st);
220
+ if (s === "ok" || s === "completed") ok++;
221
+ else if (s === "partial") partial++;
222
+ else if (s === "failed") failed++;
223
+ else if (s === "running" || s === "in_progress") running++;
224
+ }
225
+ return { ok, partial, failed, running };
226
+ }
227
+
228
+ // ── 뷰포트 해상도 ────────────────────────────────────────────────────────
229
+ export function resolveViewportColumns(opts = {}) {
230
+ const { columns, stream } = opts;
231
+ const v = Number.isFinite(columns)
232
+ ? columns
233
+ : Number.isFinite(stream?.columns)
234
+ ? stream.columns
235
+ : Number.isFinite(process.stdout?.columns)
236
+ ? process.stdout.columns
237
+ : FALLBACK_COLUMNS;
238
+ return Math.max(48, v || FALLBACK_COLUMNS);
239
+ }
240
+
241
+ export function resolveViewportRows(opts = {}) {
242
+ const { rows, stream } = opts;
243
+ const v = Number.isFinite(rows)
244
+ ? rows
245
+ : Number.isFinite(stream?.rows)
246
+ ? stream.rows
247
+ : Number.isFinite(process.stdout?.rows)
248
+ ? process.stdout.rows
249
+ : FALLBACK_ROWS;
250
+ return Math.max(10, v || FALLBACK_ROWS);
251
+ }
252
+
253
+ // ── 텍스트 래핑 ───────────────────────────────────────────────────────────
254
+ export function wrapLine(text, width) {
255
+ const limit = Math.max(8, width);
256
+ const source = String(text || "").trim();
257
+ if (!source) return [""];
258
+ const words = source.split(/\s+/);
259
+ const lines = [];
260
+ let current = "";
261
+ for (const word of words) {
262
+ const candidate = current ? `${current} ${word}` : word;
263
+ if (wcswidth(candidate) <= limit) {
264
+ current = candidate;
265
+ continue;
266
+ }
267
+ if (current) {
268
+ lines.push(current);
269
+ current = "";
270
+ }
271
+ if (wcswidth(word) <= limit) {
272
+ current = word;
273
+ continue;
274
+ }
275
+ let offset = 0;
276
+ while (offset < word.length) {
277
+ lines.push(word.slice(offset, offset + limit));
278
+ offset += limit;
279
+ }
280
+ }
281
+ if (current) lines.push(current);
282
+ return lines.length > 0 ? lines : [source.slice(0, limit)];
283
+ }
284
+
285
+ export function wrapText(text, width, rawMode = false) {
286
+ const input = sanitizeTextBlock(text, rawMode);
287
+ if (!input) return [];
288
+ return input
289
+ .split("\n")
290
+ .flatMap((line) => wrapLine(line, width))
291
+ .filter(Boolean);
292
+ }