@triflux/remote 10.51.0 → 10.53.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 (62) hide show
  1. package/cto/brief.mjs +0 -8
  2. package/cto/collect.mjs +1 -127
  3. package/cto/current.schema.json +2 -19
  4. package/cto/hygiene.mjs +2 -61
  5. package/cto/lake-root.mjs +0 -56
  6. package/cto/status.mjs +5 -139
  7. package/hub/index.mjs +0 -9
  8. package/hub/team/agents-row-attach.py +120 -0
  9. package/hub/team/agents-row.mjs +200 -0
  10. package/hub/team/claude-daemon-control.mjs +1 -2
  11. package/hub/team/claude-session-projection.mjs +5 -73
  12. package/hub/team/claude-transcript.mjs +19 -0
  13. package/hub/team/cli/commands/debug.mjs +1 -2
  14. package/hub/team/cli/commands/start/index.mjs +2 -1
  15. package/hub/team/cli/commands/start/start-headless.mjs +2 -0
  16. package/hub/team/cli/commands/start/start-mux.mjs +2 -4
  17. package/hub/team/cli/services/state-store.mjs +5 -20
  18. package/hub/team/headless.mjs +132 -551
  19. package/hub/team/psmux.mjs +3 -33
  20. package/hub/team/results-index.mjs +92 -0
  21. package/hub/team/session-context.mjs +1 -1
  22. package/hub/team/tui-viewer.mjs +9 -56
  23. package/hub/team/tui.mjs +0 -37
  24. package/hub/team/uds-orchestrator.mjs +20 -599
  25. package/hub/workers/factory.mjs +6 -51
  26. package/hub/workers/interface.mjs +1 -7
  27. package/hub/workers/lib/jsonrpc-core.mjs +11 -0
  28. package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -6
  29. package/package.json +3 -8
  30. package/scripts/lib/agent-route-policy.mjs +0 -67
  31. package/scripts/lib/cli-claude.mjs +0 -12
  32. package/scripts/lib/env-probe.mjs +0 -70
  33. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  34. package/scripts/lib/mcp-guard-engine.mjs +42 -101
  35. package/hub/hub-lifecycle.mjs +0 -248
  36. package/hub/pipe.mjs +0 -825
  37. package/hub/promote-penalties.mjs +0 -138
  38. package/hub/public/dashboard.html +0 -416
  39. package/hub/schema.sql +0 -209
  40. package/hub/server.mjs +0 -3048
  41. package/hub/store-adapter.mjs +0 -182
  42. package/hub/store.mjs +0 -1736
  43. package/hub/team/cli/services/hub-client.mjs +0 -178
  44. package/hub/team/conductor-registry.mjs +0 -121
  45. package/hub/team/cto-auto-collect.mjs +0 -115
  46. package/hub/team/lead-control.mjs +0 -191
  47. package/hub/team/session-sync.mjs +0 -316
  48. package/hub/team/swarm-intent.mjs +0 -18
  49. package/hub/team/synapse-cli.mjs +0 -458
  50. package/hub/team/synapse-http.mjs +0 -311
  51. package/hub/team/synapse-registry.mjs +0 -618
  52. package/hub/team/tui-synapse.mjs +0 -223
  53. package/hub/team/worker-sandbox.mjs +0 -125
  54. package/hub/tools.mjs +0 -900
  55. package/hub/workers/codex-app-server-worker.mjs +0 -1067
  56. package/hub/workers/delegator-mcp.mjs +0 -1098
  57. package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
  58. package/scripts/lib/claudemd-scanner.mjs +0 -26
  59. package/scripts/lib/context.mjs +0 -51
  60. package/scripts/lib/handoff.mjs +0 -187
  61. package/scripts/lib/logger.mjs +0 -122
  62. package/scripts/lib/stealth-fetch.mjs +0 -176
@@ -1,223 +0,0 @@
1
- // hub/team/tui-synapse.mjs — Synapse 실시간 관제 (Phase 3)
2
- // HTTP polling 기반 이벤트 수신 + 메트릭 수집 + 스파크라인 렌더링
3
-
4
- import { color, dim, MOCHA } from "./ansi.mjs";
5
- import { sparkline } from "./tui-widgets.mjs";
6
-
7
- const DEFAULT_SYNAPSE_BASE_URL = "http://127.0.0.1:27888";
8
- const DEFAULT_POLL_INTERVAL_MS = 2000;
9
- const MAX_METRIC_SAMPLES = 30;
10
-
11
- // ── SynapseEventStream ────────────────────────────────────────────────────
12
- /**
13
- * Synapse 서버로부터 이벤트를 polling으로 수신
14
- * @param {object} [opts]
15
- * @param {string} [opts.baseUrl] - Synapse 서버 URL
16
- * @param {number} [opts.pollIntervalMs] - polling 간격
17
- * @param {function} [opts.fetchImpl] - fetch 구현 (테스트용)
18
- * @param {function} [opts.onEvent] - 이벤트 콜백
19
- * @param {function} [opts.onError] - 에러 콜백
20
- */
21
- export function createSynapseEventStream(opts = {}) {
22
- const {
23
- baseUrl = DEFAULT_SYNAPSE_BASE_URL,
24
- pollIntervalMs = DEFAULT_POLL_INTERVAL_MS,
25
- onEvent,
26
- onError,
27
- } = opts;
28
-
29
- const fetchImpl = opts.fetchImpl || globalThis.fetch?.bind(globalThis);
30
- let timer = null;
31
- let lastEventId = 0;
32
- let running = false;
33
-
34
- async function poll(force = false) {
35
- if (!fetchImpl || (!running && !force)) return;
36
- try {
37
- const url = new URL("/synapse/events", baseUrl);
38
- url.searchParams.set("since", String(lastEventId));
39
- const res = await fetchImpl(url.toString(), {
40
- method: "GET",
41
- headers: { accept: "application/json" },
42
- signal: AbortSignal.timeout?.(5000),
43
- });
44
- if (!res.ok) return;
45
- const data = await res.json();
46
- if (Array.isArray(data.events)) {
47
- for (const event of data.events) {
48
- if (event.id > lastEventId) lastEventId = event.id;
49
- onEvent?.(event);
50
- }
51
- }
52
- } catch (err) {
53
- onError?.(err);
54
- }
55
- }
56
-
57
- return {
58
- start() {
59
- if (running) return;
60
- running = true;
61
- // 즉시 첫 poll + 주기적 반복
62
- poll();
63
- timer = setInterval(poll, pollIntervalMs);
64
- if (timer.unref) timer.unref();
65
- },
66
-
67
- stop() {
68
- running = false;
69
- if (timer) {
70
- clearInterval(timer);
71
- timer = null;
72
- }
73
- },
74
-
75
- get isRunning() {
76
- return running;
77
- },
78
-
79
- /** 테스트/수동 용: 즉시 poll 실행 (running 상태 무관) */
80
- async pollOnce() {
81
- await poll(true);
82
- },
83
-
84
- reset() {
85
- lastEventId = 0;
86
- },
87
- };
88
- }
89
-
90
- // ── MetricsCollector ──────────────────────────────────────────────────────
91
- /**
92
- * Synapse 이벤트에서 메트릭(토큰, 지연시간, 성공률)을 수집
93
- */
94
- export function createMetricsCollector(opts = {}) {
95
- const { maxSamples = MAX_METRIC_SAMPLES } = opts;
96
-
97
- const metrics = {
98
- tokenRates: [], // 초당 토큰 소비율
99
- latencies: [], // 요청 지연시간 (ms)
100
- successRates: [], // 성공률 (0-1)
101
- eventCount: 0,
102
- lastEventAt: 0,
103
- };
104
-
105
- function pushSample(arr, value) {
106
- arr.push(value);
107
- if (arr.length > maxSamples) arr.shift();
108
- }
109
-
110
- return {
111
- /** Synapse 이벤트를 처리하여 메트릭 갱신 */
112
- ingest(event) {
113
- if (!event || typeof event !== "object") return;
114
- metrics.eventCount++;
115
- metrics.lastEventAt = Date.now();
116
-
117
- // 토큰 소비율
118
- if (typeof event.tokens === "number" && event.tokens > 0) {
119
- const elapsed = event.elapsed || 1;
120
- pushSample(metrics.tokenRates, event.tokens / elapsed);
121
- }
122
-
123
- // 지연시간
124
- if (typeof event.latencyMs === "number") {
125
- pushSample(metrics.latencies, event.latencyMs);
126
- }
127
-
128
- // 성공률 (이벤트별 ok/fail)
129
- if (event.status) {
130
- const ok =
131
- event.status === "ok" || event.status === "completed" ? 1 : 0;
132
- pushSample(metrics.successRates, ok);
133
- }
134
- },
135
-
136
- /** 현재 메트릭 스냅샷 반환 */
137
- snapshot() {
138
- const avgLatency =
139
- metrics.latencies.length > 0
140
- ? metrics.latencies.reduce((a, b) => a + b, 0) /
141
- metrics.latencies.length
142
- : 0;
143
- const avgSuccessRate =
144
- metrics.successRates.length > 0
145
- ? metrics.successRates.reduce((a, b) => a + b, 0) /
146
- metrics.successRates.length
147
- : 1;
148
- const lastTokenRate =
149
- metrics.tokenRates.length > 0
150
- ? metrics.tokenRates[metrics.tokenRates.length - 1]
151
- : 0;
152
-
153
- return {
154
- tokenRates: [...metrics.tokenRates],
155
- latencies: [...metrics.latencies],
156
- successRates: [...metrics.successRates],
157
- avgLatency: Math.round(avgLatency),
158
- avgSuccessRate: Math.round(avgSuccessRate * 100),
159
- lastTokenRate: Math.round(lastTokenRate),
160
- eventCount: metrics.eventCount,
161
- lastEventAt: metrics.lastEventAt,
162
- };
163
- },
164
-
165
- reset() {
166
- metrics.tokenRates.length = 0;
167
- metrics.latencies.length = 0;
168
- metrics.successRates.length = 0;
169
- metrics.eventCount = 0;
170
- metrics.lastEventAt = 0;
171
- },
172
- };
173
- }
174
-
175
- // ── Tier1 메트릭 렌더러 ───────────────────────────────────────────────────
176
- /**
177
- * Synapse 메트릭을 Tier1에 표시할 한 줄 문자열로 렌더링
178
- * @param {object} snapshot - MetricsCollector.snapshot() 결과
179
- * @param {number} [width=60] - 최대 표시 폭
180
- * @returns {string} 렌더링된 메트릭 행
181
- */
182
- export function renderMetricsTier1(snapshot, width = 60) {
183
- if (!snapshot || snapshot.eventCount === 0) {
184
- return dim("synapse: waiting for events…");
185
- }
186
-
187
- const parts = [];
188
-
189
- // 토큰 스파크라인
190
- if (snapshot.tokenRates.length > 0) {
191
- const spark = sparkline(snapshot.tokenRates, 8, MOCHA.executing);
192
- parts.push(
193
- `tok/s ${spark} ${color(String(snapshot.lastTokenRate), MOCHA.executing)}`,
194
- );
195
- }
196
-
197
- // 지연시간
198
- if (snapshot.latencies.length > 0) {
199
- const latColor =
200
- snapshot.avgLatency > 1000
201
- ? MOCHA.fail
202
- : snapshot.avgLatency > 500
203
- ? MOCHA.partial
204
- : MOCHA.ok;
205
- parts.push(`lat ${color(`${snapshot.avgLatency}ms`, latColor)}`);
206
- }
207
-
208
- // 성공률
209
- if (snapshot.successRates.length > 0) {
210
- const srColor =
211
- snapshot.avgSuccessRate < 80
212
- ? MOCHA.fail
213
- : snapshot.avgSuccessRate < 95
214
- ? MOCHA.partial
215
- : MOCHA.ok;
216
- parts.push(`ok ${color(`${snapshot.avgSuccessRate}%`, srColor)}`);
217
- }
218
-
219
- // 이벤트 카운트
220
- parts.push(dim(`ev:${snapshot.eventCount}`));
221
-
222
- return parts.join(dim(" │ "));
223
- }
@@ -1,125 +0,0 @@
1
- // hub/team/worker-sandbox.mjs — local worker HOME/APPDATA isolation helpers
2
- //
3
- // Team/swarm workers run untrusted task-specific CLIs. Keep their mutable user
4
- // state under the worker worktree instead of the operator's real home/appdata,
5
- // while preserving explicitly brokered auth homes such as CODEX_HOME.
6
-
7
- import { mkdirSync } from "node:fs";
8
- import { join, resolve, win32 } from "node:path";
9
-
10
- const SAFE_SEGMENT_RE = /[^a-zA-Z0-9._-]/g;
11
-
12
- function safeSegment(value, fallback = "worker") {
13
- const raw = String(value ?? "").trim();
14
- const cleaned = raw.replace(SAFE_SEGMENT_RE, "_").replace(/^_+|_+$/g, "");
15
- return cleaned || fallback;
16
- }
17
-
18
- function isDisabled(env = {}) {
19
- return /^(0|false|no|off)$/i.test(String(env.TFX_WORKER_SANDBOX ?? ""));
20
- }
21
-
22
- // Antigravity-family CLIs (agy/gemini) authenticate only via interactive OAuth and
23
- // store credentials in the OS keyring plus HOME-relative ~/.gemini state bound to the
24
- // logged-in user. They expose no headless-auth flag and no config-home env
25
- // (antigravity-cli issues #223/#155/#316), so overriding HOME forces a re-auth that
26
- // never completes in a headless swarm/team worker — the worker times out at the OAuth
27
- // wait and does no work (the agy "no_commit" symptom). Keep the host HOME for these
28
- // agents so the keyring and ~/.gemini resolve. Codex stays isolated via CODEX_HOME.
29
- const AUTH_HOME_BOUND_AGENTS = new Set(["antigravity", "agy", "gemini"]);
30
-
31
- function isAuthHomeBoundAgent(agent) {
32
- return AUTH_HOME_BOUND_AGENTS.has(
33
- String(agent ?? "")
34
- .trim()
35
- .toLowerCase(),
36
- );
37
- }
38
-
39
- function windowsHomeParts(home) {
40
- const normalized = String(home || "").replace(/\//g, "\\");
41
- const match = normalized.match(/^([a-zA-Z]:)(\\.*)$/);
42
- if (!match) return null;
43
- return { drive: match[1], path: match[2] || "\\" };
44
- }
45
-
46
- function mkdirAll(paths) {
47
- for (const path of paths) mkdirSync(path, { recursive: true });
48
- }
49
-
50
- /**
51
- * Build a deterministic sandbox home for a local team/swarm worker.
52
- *
53
- * @param {object} opts
54
- * @param {string} [opts.cwd] Worktree/current working directory for the worker.
55
- * @param {string} [opts.sessionId] Stable session/member id.
56
- * @param {string} [opts.agent] Worker CLI/agent; antigravity-family agents skip the
57
- * HOME override so their keyring/OAuth credentials resolve (see note above).
58
- * @param {object} [opts.env] Existing env used for opt-out and explicit root.
59
- * @param {boolean} [opts.create=true] Create directories eagerly.
60
- * @returns {{env: object, root: string|null, home: string|null, disabled: boolean, reason?: string}}
61
- */
62
- export function buildWorkerSandboxEnv(opts = {}) {
63
- const env = opts.env && typeof opts.env === "object" ? opts.env : {};
64
- if (isDisabled(env)) {
65
- return { env: {}, root: null, home: null, disabled: true };
66
- }
67
- if (isAuthHomeBoundAgent(opts.agent)) {
68
- return {
69
- env: {},
70
- root: null,
71
- home: null,
72
- disabled: true,
73
- reason: "auth-home-bound-agent",
74
- };
75
- }
76
-
77
- const cwd = resolve(opts.cwd || process.cwd());
78
- const sessionId = safeSegment(opts.sessionId, "worker");
79
- const home = resolve(
80
- env.TFX_WORKER_HOME || join(cwd, ".triflux", "worker-home", sessionId),
81
- );
82
- const appData = join(home, "AppData", "Roaming");
83
- const localAppData = join(home, "AppData", "Local");
84
- const xdgConfig = join(home, ".config");
85
- const xdgCache = join(home, ".cache");
86
- const xdgState = join(home, ".local", "state");
87
-
88
- if (opts.create !== false) {
89
- mkdirAll([home, appData, localAppData, xdgConfig, xdgCache, xdgState]);
90
- }
91
-
92
- const overlay = {
93
- TFX_WORKER_HOME: home,
94
- HOME: home,
95
- USERPROFILE: home,
96
- APPDATA: appData,
97
- LOCALAPPDATA: localAppData,
98
- XDG_CONFIG_HOME: xdgConfig,
99
- XDG_CACHE_HOME: xdgCache,
100
- XDG_STATE_HOME: xdgState,
101
- };
102
- const hostHome = env.HOME || env.USERPROFILE;
103
- if (!env.CODEX_HOME && hostHome) {
104
- overlay.CODEX_HOME = join(hostHome, ".codex");
105
- }
106
-
107
- const winParts =
108
- windowsHomeParts(home) ||
109
- (process.platform === "win32"
110
- ? {
111
- drive: win32.parse(home).root.replace(/[\\/]$/, "") || "C:",
112
- path:
113
- win32
114
- .relative(win32.parse(home).root, home)
115
- .replace(/\//g, "\\")
116
- .replace(/^/, "\\") || "\\",
117
- }
118
- : null);
119
- if (winParts) {
120
- overlay.HOMEDRIVE = winParts.drive;
121
- overlay.HOMEPATH = winParts.path;
122
- }
123
-
124
- return { env: overlay, root: home, home, disabled: false };
125
- }