@triflux/remote 10.50.2 → 10.52.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 (134) hide show
  1. package/cto/brief.mjs +0 -20
  2. package/cto/collect.mjs +1 -200
  3. package/cto/current.schema.json +2 -23
  4. package/cto/hygiene.mjs +2 -61
  5. package/cto/lake-root.mjs +0 -56
  6. package/cto/status.mjs +5 -187
  7. package/hub/index.mjs +0 -17
  8. package/hub/team/agent-map.json +0 -1
  9. package/hub/team/agents-row-attach.py +120 -0
  10. package/hub/team/agents-row.mjs +200 -0
  11. package/hub/team/ansi.mjs +1 -35
  12. package/hub/team/backend.mjs +9 -145
  13. package/hub/team/claude-daemon-control.mjs +1 -2
  14. package/hub/team/claude-session-projection.mjs +5 -73
  15. package/hub/team/cli/commands/attach.mjs +1 -17
  16. package/hub/team/cli/commands/control.mjs +12 -38
  17. package/hub/team/cli/commands/debug.mjs +2 -39
  18. package/hub/team/cli/commands/focus.mjs +5 -31
  19. package/hub/team/cli/commands/interrupt.mjs +6 -25
  20. package/hub/team/cli/commands/kill.mjs +1 -30
  21. package/hub/team/cli/commands/list.mjs +0 -16
  22. package/hub/team/cli/commands/send.mjs +6 -26
  23. package/hub/team/cli/commands/start/index.mjs +42 -133
  24. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  25. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  26. package/hub/team/cli/commands/start/start-mux.mjs +2 -7
  27. package/hub/team/cli/commands/status.mjs +2 -57
  28. package/hub/team/cli/commands/stop.mjs +14 -19
  29. package/hub/team/cli/help.mjs +4 -5
  30. package/hub/team/cli/manifest.mjs +5 -1
  31. package/hub/team/cli/render.mjs +0 -12
  32. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  33. package/hub/team/cli/services/state-store.mjs +5 -20
  34. package/hub/team/handoff.mjs +3 -34
  35. package/hub/team/headless.mjs +108 -1296
  36. package/hub/team/orchestrator.mjs +4 -30
  37. package/hub/team/pane.mjs +6 -28
  38. package/hub/team/psmux.mjs +3 -34
  39. package/hub/team/remote-session.mjs +1 -2
  40. package/hub/team/session-context.mjs +1 -1
  41. package/hub/team/session.mjs +7 -91
  42. package/hub/team/tui-core.mjs +1 -1
  43. package/hub/team/tui-viewer.mjs +11 -58
  44. package/hub/team/tui.mjs +8 -306
  45. package/hub/team/uds-orchestrator.mjs +2 -580
  46. package/hub/team/wt-manager.mjs +2 -2
  47. package/hub/workers/factory.mjs +6 -84
  48. package/hub/workers/interface.mjs +1 -7
  49. package/hub/workers/lib/jsonrpc-core.mjs +11 -0
  50. package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -8
  51. package/package.json +3 -8
  52. package/scripts/lib/agent-route-policy.mjs +143 -62
  53. package/scripts/lib/cli-claude.mjs +0 -14
  54. package/scripts/lib/env-probe.mjs +2 -131
  55. package/scripts/lib/gemini-profiles.mjs +2 -69
  56. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  57. package/scripts/lib/machine-profile.mjs +3 -17
  58. package/scripts/lib/mcp-filter.mjs +109 -53
  59. package/scripts/lib/mcp-guard-engine.mjs +40 -98
  60. package/scripts/lib/mcp-health.mjs +2 -2
  61. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  62. package/scripts/lib/psmux-info.mjs +11 -59
  63. package/scripts/lib/skill-template.mjs +0 -245
  64. package/hub/hub-lifecycle.mjs +0 -248
  65. package/hub/pipe.mjs +0 -825
  66. package/hub/promote-penalties.mjs +0 -138
  67. package/hub/public/dashboard.html +0 -416
  68. package/hub/schema.sql +0 -209
  69. package/hub/server.mjs +0 -3048
  70. package/hub/store-adapter.mjs +0 -182
  71. package/hub/store.mjs +0 -1736
  72. package/hub/team/build-worker-prompt.mjs +0 -92
  73. package/hub/team/check-mcp-hub.mjs +0 -49
  74. package/hub/team/claude-native-bridge.mjs +0 -987
  75. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  76. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  77. package/hub/team/cli/services/hub-client.mjs +0 -264
  78. package/hub/team/cli/services/native-control.mjs +0 -145
  79. package/hub/team/codex-review.mjs +0 -520
  80. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  81. package/hub/team/conductor-registry.mjs +0 -121
  82. package/hub/team/conductor.mjs +0 -1529
  83. package/hub/team/consensus-meta.mjs +0 -176
  84. package/hub/team/cto-auto-collect.mjs +0 -115
  85. package/hub/team/cto-pull.mjs +0 -31
  86. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  87. package/hub/team/dashboard.mjs +0 -322
  88. package/hub/team/event-log.mjs +0 -84
  89. package/hub/team/execution-mode.mjs +0 -324
  90. package/hub/team/extract-completion-payload.mjs +0 -110
  91. package/hub/team/headless-bridge-session.mjs +0 -17
  92. package/hub/team/health-probe.mjs +0 -435
  93. package/hub/team/interactive-native-launcher.mjs +0 -119
  94. package/hub/team/interactive-native-worker.mjs +0 -80
  95. package/hub/team/interactive-tui-transport.mjs +0 -479
  96. package/hub/team/launcher-template.mjs +0 -144
  97. package/hub/team/lead-control.mjs +0 -191
  98. package/hub/team/mcp-selector.mjs +0 -145
  99. package/hub/team/native-supervisor.mjs +0 -460
  100. package/hub/team/native.mjs +0 -727
  101. package/hub/team/recovery-store.mjs +0 -149
  102. package/hub/team/remote-probe.mjs +0 -292
  103. package/hub/team/remote-watcher.mjs +0 -506
  104. package/hub/team/runtime-strategy.mjs +0 -200
  105. package/hub/team/schemas/worker-completion.json +0 -39
  106. package/hub/team/sentinel-capture.mjs +0 -127
  107. package/hub/team/session-sync.mjs +0 -316
  108. package/hub/team/swarm-cli.mjs +0 -390
  109. package/hub/team/swarm-hypervisor.mjs +0 -2206
  110. package/hub/team/swarm-intent.mjs +0 -216
  111. package/hub/team/swarm-locks.mjs +0 -335
  112. package/hub/team/swarm-planner.mjs +0 -371
  113. package/hub/team/swarm-preflight.mjs +0 -366
  114. package/hub/team/swarm-reconciler.mjs +0 -242
  115. package/hub/team/synapse-cli.mjs +0 -458
  116. package/hub/team/synapse-http.mjs +0 -311
  117. package/hub/team/synapse-registry.mjs +0 -618
  118. package/hub/team/tui-remote-adapter.mjs +0 -377
  119. package/hub/team/tui-synapse.mjs +0 -223
  120. package/hub/team/worker-completion-validator.mjs +0 -79
  121. package/hub/team/worker-sandbox.mjs +0 -125
  122. package/hub/team/worktree-lifecycle.mjs +0 -639
  123. package/hub/team/wt-templates.json +0 -43
  124. package/hub/tools.mjs +0 -900
  125. package/hub/workers/antigravity-route-worker.mjs +0 -179
  126. package/hub/workers/codex-app-server-worker.mjs +0 -1067
  127. package/hub/workers/delegator-mcp.mjs +0 -1098
  128. package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
  129. package/scripts/lib/claudemd-scanner.mjs +0 -223
  130. package/scripts/lib/context.mjs +0 -67
  131. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  132. package/scripts/lib/handoff.mjs +0 -187
  133. package/scripts/lib/logger.mjs +0 -122
  134. package/scripts/lib/stealth-fetch.mjs +0 -176
@@ -1,460 +0,0 @@
1
- // hub/team/native-supervisor.mjs — tmux 없이 멀티 CLI를 직접 띄우는 네이티브 팀 런타임
2
-
3
- import { execSync as execSyncSupervisor, spawn } from "node:child_process";
4
- import {
5
- createWriteStream,
6
- mkdirSync,
7
- readFileSync,
8
- writeFileSync,
9
- } from "node:fs";
10
- import { createServer } from "node:http";
11
- import { dirname, join } from "node:path";
12
- import {
13
- ensureBashScriptExecution,
14
- resolveBashExecutable,
15
- } from "@triflux/core/hub/lib/bash-path.mjs";
16
- import { verifySlimWrapperRouteExecution } from "./native.mjs";
17
- import { forceCleanupTeam } from "./nativeProxy.mjs";
18
- import { buildWorkerSandboxEnv } from "./worker-sandbox.mjs";
19
-
20
- const ROUTE_LOG_TAIL_BYTES = 65536;
21
-
22
- function parseArgs(argv) {
23
- const out = {};
24
- for (let i = 0; i < argv.length; i++) {
25
- const cur = argv[i];
26
- if (cur === "--config" && argv[i + 1]) {
27
- out.config = argv[++i];
28
- }
29
- }
30
- return out;
31
- }
32
-
33
- async function readJson(path) {
34
- return JSON.parse(readFileSync(path, "utf8"));
35
- }
36
-
37
- function safeText(v, fallback = "") {
38
- if (v == null) return fallback;
39
- return String(v);
40
- }
41
-
42
- function readTailText(path, maxBytes = ROUTE_LOG_TAIL_BYTES) {
43
- try {
44
- const raw = readFileSync(path, "utf8");
45
- if (raw.length <= maxBytes) return raw;
46
- return raw.slice(-maxBytes);
47
- } catch {
48
- return "";
49
- }
50
- }
51
-
52
- function finalizeRouteVerification(state) {
53
- if (state?.member?.role !== "worker") return;
54
-
55
- const verification = verifySlimWrapperRouteExecution({
56
- promptText: safeText(state.member?.prompt),
57
- stdoutText: readTailText(state.logFile),
58
- stderrText: readTailText(state.errFile),
59
- });
60
-
61
- state.routeVerification = verification;
62
- if (!verification.expectedRouteInvocation) {
63
- state.completionStatus = "unchecked";
64
- state.completionReason = null;
65
- return;
66
- }
67
-
68
- state.completionStatus = verification.abnormal ? "abnormal" : "normal";
69
- state.completionReason = verification.reason;
70
- if (verification.abnormal) {
71
- state.lastPreview = "[abnormal] tfx-route.sh evidence missing";
72
- }
73
- }
74
-
75
- function nowMs() {
76
- return Date.now();
77
- }
78
-
79
- const args = parseArgs(process.argv.slice(2));
80
- if (!args.config) {
81
- console.error("사용법: node native-supervisor.mjs --config <path>");
82
- process.exit(1);
83
- }
84
-
85
- const config = await readJson(args.config);
86
- const {
87
- sessionName,
88
- teamName = sessionName,
89
- runtimeFile,
90
- logsDir,
91
- startupDelayMs = 3000,
92
- members = [],
93
- } = config;
94
-
95
- mkdirSync(logsDir, { recursive: true });
96
- mkdirSync(dirname(runtimeFile), { recursive: true });
97
-
98
- const startedAt = nowMs();
99
- const processMap = new Map();
100
-
101
- function memberStateSnapshot() {
102
- const states = [];
103
- for (const m of members) {
104
- const state = processMap.get(m.name);
105
- states.push({
106
- name: m.name,
107
- role: m.role,
108
- cli: m.cli,
109
- agentId: m.agentId,
110
- command: m.command,
111
- pid: state?.child?.pid || null,
112
- status: state?.status || "unknown",
113
- exitCode: state?.exitCode ?? null,
114
- lastPreview: state?.lastPreview || "",
115
- completionStatus: state?.completionStatus || null,
116
- completionReason: state?.completionReason || null,
117
- routeVerification: state?.routeVerification || null,
118
- logFile: state?.logFile || null,
119
- errFile: state?.errFile || null,
120
- workerSandboxRoot: state?.workerSandboxRoot || null,
121
- });
122
- }
123
- return states;
124
- }
125
-
126
- function writeRuntime(controlPort) {
127
- const runtime = {
128
- sessionName,
129
- supervisorPid: process.pid,
130
- controlUrl: `http://127.0.0.1:${controlPort}`,
131
- startedAt,
132
- members: memberStateSnapshot(),
133
- };
134
- writeFileSync(runtimeFile, JSON.stringify(runtime, null, 2) + "\n");
135
- }
136
-
137
- // Shell metacharacters that can be used for command injection.
138
- // member.command is a CLI invocation string (e.g. "codex --flag value").
139
- // shell: true is required on Windows for .cmd executables, so we validate
140
- // the command string instead of removing the shell option.
141
- const SAFE_COMMAND_RE = /^[a-zA-Z0-9 _./:@"'=\-\\]+$/;
142
-
143
- function validateMemberCommand(command, memberName) {
144
- if (typeof command !== "string" || command.trim().length === 0) {
145
- throw new Error(
146
- `member "${memberName}": command must be a non-empty string`,
147
- );
148
- }
149
- if (!SAFE_COMMAND_RE.test(command)) {
150
- throw new Error(
151
- `member "${memberName}": command contains disallowed characters — ` +
152
- `shell metacharacters (;&|$\`()<>{}\\n\\r) are not permitted`,
153
- );
154
- }
155
- }
156
-
157
- function spawnMember(member) {
158
- const command = ensureBashScriptExecution(member.command, {
159
- bashCommand: resolveBashExecutable(),
160
- });
161
- validateMemberCommand(command, member.name);
162
-
163
- const outPath = join(logsDir, `${member.name}.out.log`);
164
- const errPath = join(logsDir, `${member.name}.err.log`);
165
-
166
- const outWs = createWriteStream(outPath, { flags: "a" });
167
- const errWs = createWriteStream(errPath, { flags: "a" });
168
-
169
- const baseEnv = {
170
- ...process.env,
171
- TERM:
172
- process.env.TERM && process.env.TERM !== "dumb"
173
- ? process.env.TERM
174
- : "xterm-256color",
175
- };
176
- // Worker members get HOME-isolated sandboxes, but antigravity-family agents
177
- // (agy/gemini) are carved out inside buildWorkerSandboxEnv so their keyring/
178
- // OAuth auth resolves — pass member.cli so the carve-out applies in-process too.
179
- const sandbox =
180
- member.role === "worker"
181
- ? buildWorkerSandboxEnv({
182
- cwd: config.workdir || process.cwd(),
183
- sessionId: `${sessionName}-${member.name}`,
184
- agent: member.cli,
185
- env: baseEnv,
186
- })
187
- : { env: {}, root: null };
188
-
189
- const child = spawn(command, {
190
- shell: true,
191
- env: { ...baseEnv, ...sandbox.env },
192
- stdio: ["pipe", "pipe", "pipe"],
193
- windowsHide: true,
194
- });
195
-
196
- const state = {
197
- member,
198
- child,
199
- outWs,
200
- errWs,
201
- logFile: outPath,
202
- errFile: errPath,
203
- status: "running",
204
- exitCode: null,
205
- lastPreview: "",
206
- workerSandboxRoot: sandbox.root || null,
207
- };
208
-
209
- child.stdout.on("data", (buf) => {
210
- outWs.write(buf);
211
- const txt = safeText(buf).trim();
212
- if (txt) {
213
- const lines = txt.split(/\r?\n/).filter(Boolean);
214
- if (lines.length)
215
- state.lastPreview = lines[lines.length - 1].slice(0, 280);
216
- }
217
- });
218
-
219
- child.stderr.on("data", (buf) => {
220
- errWs.write(buf);
221
- const txt = safeText(buf).trim();
222
- if (txt) {
223
- const lines = txt.split(/\r?\n/).filter(Boolean);
224
- if (lines.length)
225
- state.lastPreview = `[err] ${lines[lines.length - 1].slice(0, 260)}`;
226
- }
227
- });
228
-
229
- child.on("exit", (code) => {
230
- state.status = "exited";
231
- state.exitCode = code;
232
- finalizeRouteVerification(state);
233
- try {
234
- outWs.end();
235
- } catch {}
236
- try {
237
- errWs.end();
238
- } catch {}
239
- maybeAutoShutdown();
240
- });
241
-
242
- child.on("error", (err) => {
243
- state.status = "exited";
244
- state.exitCode = -1;
245
- state.lastPreview = `[spawn error] ${err.message}`;
246
- try {
247
- outWs.end();
248
- } catch {}
249
- try {
250
- errWs.end();
251
- } catch {}
252
- maybeAutoShutdown();
253
- });
254
-
255
- processMap.set(member.name, state);
256
- }
257
-
258
- function sendInput(memberName, text) {
259
- const state = processMap.get(memberName);
260
- if (!state) return { ok: false, error: "member_not_found" };
261
- if (state.status !== "running")
262
- return { ok: false, error: "member_not_running" };
263
- try {
264
- state.child.stdin.write(`${safeText(text)}\n`);
265
- return { ok: true };
266
- } catch (e) {
267
- return { ok: false, error: e.message };
268
- }
269
- }
270
-
271
- function interruptMember(memberName) {
272
- const state = processMap.get(memberName);
273
- if (!state) return { ok: false, error: "member_not_found" };
274
- if (state.status !== "running")
275
- return { ok: false, error: "member_not_running" };
276
-
277
- let signaled = false;
278
- try {
279
- signaled = state.child.kill("SIGINT");
280
- } catch {
281
- signaled = false;
282
- }
283
-
284
- if (!signaled) {
285
- try {
286
- state.child.stdin.write("\u0003");
287
- signaled = true;
288
- } catch {
289
- signaled = false;
290
- }
291
- }
292
-
293
- return signaled ? { ok: true } : { ok: false, error: "interrupt_failed" };
294
- }
295
-
296
- let isShuttingDown = false;
297
-
298
- function maybeAutoShutdown() {
299
- if (isShuttingDown) return;
300
- const allExited = [...processMap.values()].every(
301
- (s) => s.status === "exited",
302
- );
303
- if (!allExited) return;
304
- shutdown();
305
- }
306
-
307
- async function shutdown() {
308
- if (isShuttingDown) return;
309
- isShuttingDown = true;
310
-
311
- for (const state of processMap.values()) {
312
- if (state.status === "running") {
313
- try {
314
- state.child.stdin.write("exit\n");
315
- } catch {}
316
- try {
317
- state.child.kill("SIGTERM");
318
- } catch {}
319
- }
320
- try {
321
- state.outWs.end();
322
- } catch {}
323
- try {
324
- state.errWs.end();
325
- } catch {}
326
- }
327
-
328
- try {
329
- await forceCleanupTeam(teamName);
330
- } catch {}
331
-
332
- setTimeout(() => {
333
- for (const state of processMap.values()) {
334
- if (state.status === "running") {
335
- const pid = state.child?.pid;
336
- if (process.platform === "win32" && Number.isInteger(pid) && pid > 0) {
337
- // Windows: 프로세스 트리 전체 강제 종료 (손자 MCP 서버 포함)
338
- try {
339
- execSyncSupervisor(`taskkill /T /F /PID ${pid}`, {
340
- stdio: "pipe",
341
- windowsHide: true,
342
- timeout: 5000,
343
- });
344
- } catch {}
345
- } else {
346
- try {
347
- state.child.kill("SIGKILL");
348
- } catch {}
349
- }
350
- }
351
- }
352
- process.exit(0);
353
- }, 1200).unref();
354
- }
355
-
356
- for (const member of members) {
357
- spawnMember(member);
358
- }
359
-
360
- const server = createServer(async (req, res) => {
361
- const send = (code, obj) => {
362
- res.writeHead(code, { "Content-Type": "application/json" });
363
- res.end(JSON.stringify(obj));
364
- };
365
-
366
- if (req.method === "GET" && (req.url === "/" || req.url === "/status")) {
367
- return send(200, {
368
- ok: true,
369
- data: {
370
- sessionName,
371
- supervisorPid: process.pid,
372
- uptimeMs: nowMs() - startedAt,
373
- members: memberStateSnapshot(),
374
- },
375
- });
376
- }
377
-
378
- if (req.method !== "POST") {
379
- return send(405, { ok: false, error: "method_not_allowed" });
380
- }
381
-
382
- let body = {};
383
- try {
384
- const MAX_BODY = 1024 * 1024;
385
- const chunks = [];
386
- let totalLen = 0;
387
- for await (const c of req) {
388
- totalLen += c.length;
389
- if (totalLen > MAX_BODY) {
390
- send(413, { ok: false, error: "payload_too_large" });
391
- return;
392
- }
393
- chunks.push(c);
394
- }
395
- const raw = Buffer.concat(chunks).toString("utf8") || "{}";
396
- body = JSON.parse(raw);
397
- } catch {
398
- return send(400, { ok: false, error: "invalid_json" });
399
- }
400
-
401
- if (req.url === "/send") {
402
- const { member, text } = body;
403
- const r = sendInput(member, text);
404
- return send(r.ok ? 200 : 400, r);
405
- }
406
-
407
- if (req.url === "/interrupt") {
408
- const { member } = body;
409
- const r = interruptMember(member);
410
- return send(r.ok ? 200 : 400, r);
411
- }
412
-
413
- if (req.url === "/control") {
414
- const { member, command = "", reason = "" } = body;
415
- const controlMsg = `[LEAD CONTROL] command=${command}${reason ? ` reason=${reason}` : ""}`;
416
- const a = sendInput(member, controlMsg);
417
- if (!a.ok) return send(400, a);
418
- if (String(command).toLowerCase() === "interrupt") {
419
- const b = interruptMember(member);
420
- if (!b.ok) return send(400, b);
421
- }
422
- return send(200, { ok: true });
423
- }
424
-
425
- if (req.url === "/stop") {
426
- send(200, { ok: true });
427
- shutdown();
428
- return;
429
- }
430
-
431
- return send(404, { ok: false, error: "not_found" });
432
- });
433
-
434
- server.on("error", (err) => {
435
- console.error("[native-supervisor] HTTP server error:", err.message);
436
- process.exit(1);
437
- });
438
-
439
- server.listen(0, "127.0.0.1", () => {
440
- const address = server.address();
441
- const port = typeof address === "object" && address ? address.port : null;
442
- if (!port) {
443
- console.error("native supervisor 포트 바인딩 실패");
444
- process.exit(1);
445
- }
446
-
447
- writeRuntime(port);
448
-
449
- // CLI 초기화 후 프롬프트 주입
450
- setTimeout(() => {
451
- for (const m of members) {
452
- if (m.prompt) {
453
- sendInput(m.name, m.prompt);
454
- }
455
- }
456
- }, startupDelayMs).unref();
457
- });
458
-
459
- process.on("SIGINT", shutdown);
460
- process.on("SIGTERM", shutdown);