@triflux/remote 10.50.2 → 10.51.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.
- package/cto/brief.mjs +0 -12
- package/cto/collect.mjs +0 -73
- package/cto/current.schema.json +0 -4
- package/cto/status.mjs +2 -50
- package/hub/index.mjs +0 -8
- package/hub/team/agent-map.json +0 -1
- package/hub/team/ansi.mjs +1 -35
- package/hub/team/backend.mjs +9 -145
- package/hub/team/cli/commands/attach.mjs +1 -17
- package/hub/team/cli/commands/control.mjs +12 -38
- package/hub/team/cli/commands/debug.mjs +1 -37
- package/hub/team/cli/commands/focus.mjs +5 -31
- package/hub/team/cli/commands/interrupt.mjs +6 -25
- package/hub/team/cli/commands/kill.mjs +1 -30
- package/hub/team/cli/commands/list.mjs +0 -16
- package/hub/team/cli/commands/send.mjs +6 -26
- package/hub/team/cli/commands/start/index.mjs +41 -133
- package/hub/team/cli/commands/start/parse-args.mjs +15 -40
- package/hub/team/cli/commands/start/start-headless.mjs +138 -105
- package/hub/team/cli/commands/start/start-mux.mjs +0 -3
- package/hub/team/cli/commands/status.mjs +2 -57
- package/hub/team/cli/commands/stop.mjs +14 -19
- package/hub/team/cli/help.mjs +4 -5
- package/hub/team/cli/manifest.mjs +5 -1
- package/hub/team/cli/render.mjs +0 -12
- package/hub/team/cli/services/hub-client.mjs +2 -88
- package/hub/team/cli/services/runtime-mode.mjs +27 -98
- package/hub/team/handoff.mjs +3 -34
- package/hub/team/headless.mjs +13 -754
- package/hub/team/orchestrator.mjs +4 -30
- package/hub/team/pane.mjs +6 -28
- package/hub/team/psmux.mjs +0 -1
- package/hub/team/remote-session.mjs +1 -2
- package/hub/team/session.mjs +7 -91
- package/hub/team/swarm-intent.mjs +0 -198
- package/hub/team/tui-core.mjs +1 -1
- package/hub/team/tui-viewer.mjs +2 -2
- package/hub/team/tui.mjs +8 -269
- package/hub/team/wt-manager.mjs +2 -2
- package/hub/workers/factory.mjs +4 -37
- package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
- package/package.json +1 -1
- package/scripts/lib/agent-route-policy.mjs +162 -14
- package/scripts/lib/claudemd-scanner.mjs +2 -199
- package/scripts/lib/cli-claude.mjs +0 -2
- package/scripts/lib/context.mjs +3 -19
- package/scripts/lib/env-probe.mjs +5 -64
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +11 -59
- package/scripts/lib/skill-template.mjs +0 -245
- package/hub/team/build-worker-prompt.mjs +0 -92
- package/hub/team/check-mcp-hub.mjs +0 -49
- package/hub/team/claude-native-bridge.mjs +0 -987
- package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
- package/hub/team/cli/commands/start/start-wt.mjs +0 -86
- package/hub/team/cli/services/native-control.mjs +0 -145
- package/hub/team/codex-review.mjs +0 -520
- package/hub/team/conductor-mesh-bridge.mjs +0 -122
- package/hub/team/conductor.mjs +0 -1529
- package/hub/team/consensus-meta.mjs +0 -176
- package/hub/team/cto-pull.mjs +0 -31
- package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
- package/hub/team/dashboard.mjs +0 -322
- package/hub/team/event-log.mjs +0 -84
- package/hub/team/execution-mode.mjs +0 -324
- package/hub/team/extract-completion-payload.mjs +0 -110
- package/hub/team/headless-bridge-session.mjs +0 -17
- package/hub/team/health-probe.mjs +0 -435
- package/hub/team/interactive-native-launcher.mjs +0 -119
- package/hub/team/interactive-native-worker.mjs +0 -80
- package/hub/team/interactive-tui-transport.mjs +0 -479
- package/hub/team/launcher-template.mjs +0 -144
- package/hub/team/mcp-selector.mjs +0 -145
- package/hub/team/native-supervisor.mjs +0 -460
- package/hub/team/native.mjs +0 -727
- package/hub/team/recovery-store.mjs +0 -149
- package/hub/team/remote-probe.mjs +0 -292
- package/hub/team/remote-watcher.mjs +0 -506
- package/hub/team/runtime-strategy.mjs +0 -200
- package/hub/team/schemas/worker-completion.json +0 -39
- package/hub/team/sentinel-capture.mjs +0 -127
- package/hub/team/swarm-cli.mjs +0 -390
- package/hub/team/swarm-hypervisor.mjs +0 -2206
- package/hub/team/swarm-locks.mjs +0 -335
- package/hub/team/swarm-planner.mjs +0 -371
- package/hub/team/swarm-preflight.mjs +0 -366
- package/hub/team/swarm-reconciler.mjs +0 -242
- package/hub/team/tui-remote-adapter.mjs +0 -377
- package/hub/team/worker-completion-validator.mjs +0 -79
- package/hub/team/worktree-lifecycle.mjs +0 -639
- package/hub/team/wt-templates.json +0 -43
- package/hub/workers/antigravity-route-worker.mjs +0 -179
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
package/hub/team/tui.mjs
CHANGED
|
@@ -32,10 +32,10 @@ import {
|
|
|
32
32
|
cliColor,
|
|
33
33
|
normalizeWorkerState as coreNormalizeWorkerState,
|
|
34
34
|
countStatuses,
|
|
35
|
-
FALLBACK_COLUMNS,
|
|
36
|
-
FALLBACK_ROWS,
|
|
37
35
|
formatTokens,
|
|
38
36
|
loadVersion,
|
|
37
|
+
resolveViewportColumns,
|
|
38
|
+
resolveViewportRows,
|
|
39
39
|
runtimeStatus,
|
|
40
40
|
sanitizeFiles,
|
|
41
41
|
sanitizeOneLine,
|
|
@@ -52,14 +52,12 @@ import {
|
|
|
52
52
|
import {
|
|
53
53
|
createPanelResizer,
|
|
54
54
|
createSearchState,
|
|
55
|
-
createTokenTracker,
|
|
56
55
|
createVimMotion,
|
|
57
56
|
} from "./tui-widgets.mjs";
|
|
58
57
|
import { createWtManager } from "./wt-manager.mjs";
|
|
59
58
|
|
|
60
59
|
const VERSION = await loadVersion();
|
|
61
60
|
|
|
62
|
-
// FALLBACK_COLUMNS, FALLBACK_ROWS → tui-core.mjs에서 import
|
|
63
61
|
const MIN_CARD_WIDTH = 28;
|
|
64
62
|
const ATTACH_SESSION_NAME_PATTERN = /^[a-zA-Z0-9_.-]+$/u;
|
|
65
63
|
const DEFAULT_ATTACH_TAB_TTL_MS = 30_000;
|
|
@@ -284,11 +282,6 @@ function activityWave(tick, count = 4) {
|
|
|
284
282
|
return `${MOCHA.executing}${wave}${RESET}`;
|
|
285
283
|
}
|
|
286
284
|
|
|
287
|
-
const GRID_GAP = 2;
|
|
288
|
-
const DEFAULT_DETAIL_LINES = 10;
|
|
289
|
-
// Tier1 상단 고정 행 수
|
|
290
|
-
const _TIER1_ROWS = 2;
|
|
291
|
-
|
|
292
285
|
const SUMMARY_KEYS = [
|
|
293
286
|
"status",
|
|
294
287
|
"lead_action",
|
|
@@ -302,30 +295,6 @@ const SUMMARY_KEYS = [
|
|
|
302
295
|
"partial_output",
|
|
303
296
|
];
|
|
304
297
|
|
|
305
|
-
// ── 레이아웃 브레이크포인트 ──────────────────────────────────────────────
|
|
306
|
-
// 80-119: 28col rail, 120-159: 36col rail, 160+: 균등
|
|
307
|
-
function _resolveRailWidth(totalCols, columnCount) {
|
|
308
|
-
if (columnCount <= 1) return totalCols;
|
|
309
|
-
if (totalCols >= 160)
|
|
310
|
-
return Math.floor((totalCols - GRID_GAP * (columnCount - 1)) / columnCount);
|
|
311
|
-
if (totalCols >= 120)
|
|
312
|
-
return Math.min(
|
|
313
|
-
36,
|
|
314
|
-
Math.floor((totalCols - GRID_GAP * (columnCount - 1)) / columnCount),
|
|
315
|
-
);
|
|
316
|
-
return Math.min(
|
|
317
|
-
28,
|
|
318
|
-
Math.floor((totalCols - GRID_GAP * (columnCount - 1)) / columnCount),
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function _autoColumnCount(totalCols, workerCount) {
|
|
323
|
-
if (workerCount <= 1) return 1;
|
|
324
|
-
if (totalCols >= 160) return Math.min(workerCount, 3);
|
|
325
|
-
if (totalCols >= 120) return Math.min(workerCount, 2);
|
|
326
|
-
return 1;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
298
|
// 텍스트/상태/색상 유틸은 tui-core.mjs에서 import (위 참조)
|
|
330
299
|
|
|
331
300
|
// ── MOCHA RGB (gradual fade 보간용) ──
|
|
@@ -354,8 +323,6 @@ function statusToRgb(status) {
|
|
|
354
323
|
return MOCHA_RGB.muted;
|
|
355
324
|
}
|
|
356
325
|
|
|
357
|
-
const FADE_DURATION_MS = 1500;
|
|
358
|
-
const FLASH_PHASE_MS = 250;
|
|
359
326
|
const CARD_GLOW_MS = 3000;
|
|
360
327
|
|
|
361
328
|
// Effect 1: Pulse border — running 워커 보더가 heartbeat 동기 breathing
|
|
@@ -374,22 +341,6 @@ function gradientBorderFn(topRgb, bottomRgb) {
|
|
|
374
341
|
};
|
|
375
342
|
}
|
|
376
343
|
|
|
377
|
-
// Effect 3: Flash-fade border — 상태 변경 시 백색 플래시 → 페이드아웃
|
|
378
|
-
function _flashFadeBorderColor(currentStatus, prevStatus, changedAt) {
|
|
379
|
-
const elapsed = Date.now() - (changedAt || 0);
|
|
380
|
-
if (elapsed >= FADE_DURATION_MS || !prevStatus) return null;
|
|
381
|
-
const statusRgb = statusToRgb(currentStatus);
|
|
382
|
-
if (elapsed < FLASH_PHASE_MS) {
|
|
383
|
-
const t = elapsed / FLASH_PHASE_MS;
|
|
384
|
-
const bright = { r: 255, g: 255, b: 255 };
|
|
385
|
-
const c = lerpRgb(bright, statusRgb, t);
|
|
386
|
-
return `\x1b[38;2;${c.r};${c.g};${c.b}m`;
|
|
387
|
-
}
|
|
388
|
-
const t = (elapsed - FLASH_PHASE_MS) / (FADE_DURATION_MS - FLASH_PHASE_MS);
|
|
389
|
-
const c = lerpRgb(statusRgb, MOCHA_RGB.border, t);
|
|
390
|
-
return `\x1b[38;2;${c.r};${c.g};${c.b}m`;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
344
|
function easeOutCubic(t) {
|
|
394
345
|
return 1 - (1 - t) ** 3;
|
|
395
346
|
}
|
|
@@ -436,26 +387,6 @@ function dedupeRole(role, name, cli) {
|
|
|
436
387
|
|
|
437
388
|
// wrapLine, wrapTextAll → tui-core.mjs에서 import
|
|
438
389
|
|
|
439
|
-
function _wrapText(
|
|
440
|
-
text,
|
|
441
|
-
width,
|
|
442
|
-
maxLines = DEFAULT_DETAIL_LINES,
|
|
443
|
-
rawMode = false,
|
|
444
|
-
) {
|
|
445
|
-
if (maxLines <= 0) return [];
|
|
446
|
-
const input = sanitizeTextBlock(text, rawMode);
|
|
447
|
-
if (!input) return [];
|
|
448
|
-
const wrapped = input
|
|
449
|
-
.split("\n")
|
|
450
|
-
.flatMap((line) => wrapLine(line, width))
|
|
451
|
-
.filter(Boolean);
|
|
452
|
-
if (wrapped.length <= maxLines) return wrapped;
|
|
453
|
-
return [
|
|
454
|
-
...wrapped.slice(0, maxLines - 1),
|
|
455
|
-
truncate(wrapped[wrapped.length - 1], width),
|
|
456
|
-
];
|
|
457
|
-
}
|
|
458
|
-
|
|
459
390
|
// ── virtual row buffer ────────────────────────────────────────────────────
|
|
460
391
|
class RowBuffer {
|
|
461
392
|
constructor() {
|
|
@@ -927,19 +858,6 @@ function buildHelpOverlay(width, height) {
|
|
|
927
858
|
return result;
|
|
928
859
|
}
|
|
929
860
|
|
|
930
|
-
// ── joinColumns ───────────────────────────────────────────────────────────
|
|
931
|
-
function _joinColumns(blocks, gap = GRID_GAP) {
|
|
932
|
-
const maxHeight = Math.max(...blocks.map((b) => b.length));
|
|
933
|
-
return Array.from({ length: maxHeight }, (_, rowIdx) =>
|
|
934
|
-
blocks
|
|
935
|
-
.map(
|
|
936
|
-
(block) =>
|
|
937
|
-
block[rowIdx] || " ".repeat(wcswidth(stripAnsi(block[0] || ""))),
|
|
938
|
-
)
|
|
939
|
-
.join(" ".repeat(gap)),
|
|
940
|
-
);
|
|
941
|
-
}
|
|
942
|
-
|
|
943
861
|
// ── normalizeWorkerState ──────────────────────────────────────────────────
|
|
944
862
|
function normalizeWorkerState(existing, state) {
|
|
945
863
|
return coreNormalizeWorkerState(
|
|
@@ -1010,7 +928,6 @@ export function createLogDashboard(opts = {}) {
|
|
|
1010
928
|
let rawModeEnabled = false;
|
|
1011
929
|
|
|
1012
930
|
// UX 위젯 (ISSUE-14)
|
|
1013
|
-
const tokenTracker = createTokenTracker();
|
|
1014
931
|
const searchState = createSearchState();
|
|
1015
932
|
const vimMotion = createVimMotion();
|
|
1016
933
|
const panelResizer = createPanelResizer({
|
|
@@ -1046,26 +963,6 @@ export function createLogDashboard(opts = {}) {
|
|
|
1046
963
|
return Math.max(0, Math.round((now() - startedAt) / 1000));
|
|
1047
964
|
}
|
|
1048
965
|
|
|
1049
|
-
function getViewportColumns() {
|
|
1050
|
-
const v = Number.isFinite(columns)
|
|
1051
|
-
? columns
|
|
1052
|
-
: Number.isFinite(stream?.columns)
|
|
1053
|
-
? stream.columns
|
|
1054
|
-
: Number.isFinite(process.stdout?.columns)
|
|
1055
|
-
? process.stdout.columns
|
|
1056
|
-
: FALLBACK_COLUMNS;
|
|
1057
|
-
return Math.max(48, v || FALLBACK_COLUMNS);
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
function getViewportRows() {
|
|
1061
|
-
const v = Number.isFinite(stream?.rows)
|
|
1062
|
-
? stream.rows
|
|
1063
|
-
: Number.isFinite(process.stdout?.rows)
|
|
1064
|
-
? process.stdout.rows
|
|
1065
|
-
: FALLBACK_ROWS;
|
|
1066
|
-
return Math.max(10, v || FALLBACK_ROWS);
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
966
|
function visibleWorkerNames() {
|
|
1070
967
|
return [...workers.keys()].sort();
|
|
1071
968
|
}
|
|
@@ -1244,7 +1141,10 @@ export function createLogDashboard(opts = {}) {
|
|
|
1244
1141
|
if (key === "g") return;
|
|
1245
1142
|
|
|
1246
1143
|
// PgUp/PgDn: 페이지 단위 스크롤
|
|
1247
|
-
const pageSize = Math.max(
|
|
1144
|
+
const pageSize = Math.max(
|
|
1145
|
+
1,
|
|
1146
|
+
Math.floor(resolveViewportRows({ stream }) / 2),
|
|
1147
|
+
);
|
|
1248
1148
|
if (key === "\x1b[5~") {
|
|
1249
1149
|
scrollDetail(-pageSize);
|
|
1250
1150
|
return;
|
|
@@ -1442,8 +1342,8 @@ export function createLogDashboard(opts = {}) {
|
|
|
1442
1342
|
ensureSelectedWorker(names);
|
|
1443
1343
|
attachInput();
|
|
1444
1344
|
|
|
1445
|
-
const totalCols =
|
|
1446
|
-
const totalRows =
|
|
1345
|
+
const totalCols = resolveViewportColumns({ columns, stream });
|
|
1346
|
+
const totalRows = resolveViewportRows({ stream });
|
|
1447
1347
|
|
|
1448
1348
|
// Help overlay: 전체 화면 오버레이
|
|
1449
1349
|
if (helpOverlay) {
|
|
@@ -1681,9 +1581,6 @@ export function createLogDashboard(opts = {}) {
|
|
|
1681
1581
|
? existing._logSec
|
|
1682
1582
|
: (explicitElapsed ?? nowElapsedSec());
|
|
1683
1583
|
workers.set(paneName, merged);
|
|
1684
|
-
// 토큰 히스토리 추적 (스파크라인용)
|
|
1685
|
-
if (merged.tokens !== undefined)
|
|
1686
|
-
tokenTracker.record(paneName, merged.tokens);
|
|
1687
1584
|
ensureSelectedWorker(visibleWorkerNames());
|
|
1688
1585
|
// follow-tail: 새 데이터 → 자동 scroll 재계산
|
|
1689
1586
|
if (followTail) detailScrollOffset = 0;
|
|
@@ -1778,161 +1675,3 @@ export function createLogDashboard(opts = {}) {
|
|
|
1778
1675
|
},
|
|
1779
1676
|
};
|
|
1780
1677
|
}
|
|
1781
|
-
|
|
1782
|
-
// ── Conductor Tier: 세션 테이블 렌더러 ─────────────────────────────────
|
|
1783
|
-
//
|
|
1784
|
-
// renderConductorTier(snapshot, cols)
|
|
1785
|
-
// snapshot: conductor.getSnapshot() 반환 배열
|
|
1786
|
-
// cols: 터미널 폭 (기본 100)
|
|
1787
|
-
//
|
|
1788
|
-
// 레이아웃:
|
|
1789
|
-
// ┌─ CONDUCTOR ──────────────────────────────────────────┐
|
|
1790
|
-
// │ ID Agent Host Health Last Out Restarts Why │
|
|
1791
|
-
// │ abc123 codex local ■ OK 2s ago 0 │
|
|
1792
|
-
// └──────────────────────────────────────────────────────┘
|
|
1793
|
-
//
|
|
1794
|
-
// Health 색상: healthy=green, stalled=yellow, input_wait=cyan,
|
|
1795
|
-
// failed=red, dead/init/starting=dim
|
|
1796
|
-
|
|
1797
|
-
const CONDUCTOR_STATE_LABEL = {
|
|
1798
|
-
init: { label: "INIT", seq: MOCHA.subtext },
|
|
1799
|
-
starting: { label: "START", seq: MOCHA.executing },
|
|
1800
|
-
healthy: { label: "OK", seq: MOCHA.ok },
|
|
1801
|
-
stalled: { label: "STALL", seq: MOCHA.yellow },
|
|
1802
|
-
input_wait: { label: "INPUT_WAIT", seq: FG.cyan },
|
|
1803
|
-
failed: { label: "FAIL", seq: MOCHA.fail },
|
|
1804
|
-
restarting: { label: "RESTART", seq: MOCHA.partial },
|
|
1805
|
-
dead: { label: "DEAD", seq: FG.gray },
|
|
1806
|
-
completed: { label: "DONE", seq: MOCHA.ok },
|
|
1807
|
-
};
|
|
1808
|
-
|
|
1809
|
-
function conductorHealthCell(state) {
|
|
1810
|
-
const entry = CONDUCTOR_STATE_LABEL[state] || {
|
|
1811
|
-
label: state.toUpperCase(),
|
|
1812
|
-
seq: FG.gray,
|
|
1813
|
-
};
|
|
1814
|
-
return `${entry.seq}■ ${entry.label}${RESET}`;
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
function conductorRelTime(ms) {
|
|
1818
|
-
if (!ms) return "—";
|
|
1819
|
-
const sec = Math.round((Date.now() - ms) / 1000);
|
|
1820
|
-
if (sec < 0) return "—";
|
|
1821
|
-
if (sec < 60) return `${sec}s ago`;
|
|
1822
|
-
if (sec < 3600) return `${Math.floor(sec / 60)}m ago`;
|
|
1823
|
-
return `${Math.floor(sec / 3600)}h ago`;
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
/**
|
|
1827
|
-
* Conductor 세션 테이블을 문자열 배열(행 목록)로 렌더링.
|
|
1828
|
-
*
|
|
1829
|
-
* @param {object[]} snapshot — conductor.getSnapshot() 결과
|
|
1830
|
-
* @param {number} [cols=100] — 터미널 폭
|
|
1831
|
-
* @returns {string[]} 렌더링된 행 목록 (altScreen rowBuf.set()에 바로 삽입 가능)
|
|
1832
|
-
*/
|
|
1833
|
-
export function renderConductorTier(snapshot, cols = 100) {
|
|
1834
|
-
const width = Math.max(48, cols);
|
|
1835
|
-
const inner = width - 4; // border: '│ ' + content + ' │'
|
|
1836
|
-
|
|
1837
|
-
// ── 열 너비 계산 ────────────────────────────────────────
|
|
1838
|
-
// ID(8) Agent(7) Host(6) Health(dyn) LastOut(dyn) Restarts(8) Why(rest)
|
|
1839
|
-
const COL_ID = 8;
|
|
1840
|
-
const COL_AGENT = 7;
|
|
1841
|
-
const COL_HOST = 6;
|
|
1842
|
-
const COL_RESTARTS = 4;
|
|
1843
|
-
const COL_HEALTH = 12; // '■ INPUT_WAIT' = 12 chars
|
|
1844
|
-
const COL_LASTOUT = 9; // '999m ago' = 8 + space
|
|
1845
|
-
// Why gets the remainder
|
|
1846
|
-
const fixedCols =
|
|
1847
|
-
COL_ID + COL_AGENT + COL_HOST + COL_HEALTH + COL_LASTOUT + COL_RESTARTS + 6; // 6 spaces between cols
|
|
1848
|
-
const COL_WHY = Math.max(4, inner - fixedCols);
|
|
1849
|
-
|
|
1850
|
-
function cell(text, width_) {
|
|
1851
|
-
return clip(String(text ?? ""), width_);
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
function buildRow(id, agent, host, healthCell, lastOut, restarts, why) {
|
|
1855
|
-
const idC = cell(id, COL_ID);
|
|
1856
|
-
const agentC = cell(agent, COL_AGENT);
|
|
1857
|
-
const hostC = cell(host, COL_HOST);
|
|
1858
|
-
const restartsC = cell(String(restarts ?? 0), COL_RESTARTS);
|
|
1859
|
-
const lastOutC = clip(lastOut, COL_LASTOUT);
|
|
1860
|
-
const whyC = cell(why, COL_WHY);
|
|
1861
|
-
// healthCell already has ANSI codes; pad its visible width manually
|
|
1862
|
-
const healthVis = wcswidth(stripAnsi(healthCell));
|
|
1863
|
-
const healthPad = Math.max(0, COL_HEALTH - healthVis);
|
|
1864
|
-
const healthC = healthCell + " ".repeat(healthPad);
|
|
1865
|
-
|
|
1866
|
-
return `${idC} ${agentC} ${hostC} ${healthC} ${lastOutC} ${restartsC} ${whyC}`;
|
|
1867
|
-
}
|
|
1868
|
-
|
|
1869
|
-
const boxWidth = inner;
|
|
1870
|
-
|
|
1871
|
-
// ── 타이틀 행 ───────────────────────────────────────────
|
|
1872
|
-
const titleText = ` CONDUCTOR `;
|
|
1873
|
-
const titleColored = bold(color(titleText, FG.accent));
|
|
1874
|
-
// Border top with title embedded: ┌─ CONDUCTOR ──...─┐
|
|
1875
|
-
const dashLen = Math.max(0, boxWidth - titleText.length);
|
|
1876
|
-
const dashLeft = 1;
|
|
1877
|
-
const dashRight = Math.max(0, dashLen - dashLeft);
|
|
1878
|
-
const borderSeq = MOCHA.border;
|
|
1879
|
-
const topBorder = `${borderSeq}┌${"─".repeat(dashLeft)}${RESET}${titleColored}${borderSeq}${"─".repeat(dashRight)}┐${RESET}`;
|
|
1880
|
-
|
|
1881
|
-
// ── ヘッダー行 ───────────────────────────────────────────
|
|
1882
|
-
const headerRow = buildRow(
|
|
1883
|
-
"ID",
|
|
1884
|
-
"Agent",
|
|
1885
|
-
"Host",
|
|
1886
|
-
clip("Health", COL_HEALTH),
|
|
1887
|
-
"Last Out",
|
|
1888
|
-
"Rst",
|
|
1889
|
-
"Why",
|
|
1890
|
-
);
|
|
1891
|
-
const headerLine = `${borderSeq}│${RESET} ${dim(headerRow)} ${borderSeq}│${RESET}`;
|
|
1892
|
-
|
|
1893
|
-
// ── データ行 ────────────────────────────────────────────
|
|
1894
|
-
const dataLines = [];
|
|
1895
|
-
if (!snapshot || snapshot.length === 0) {
|
|
1896
|
-
const emptyMsg = color("(no sessions)", FG.muted);
|
|
1897
|
-
const _emptyPad = clip(
|
|
1898
|
-
stripAnsi(emptyMsg) === "(no sessions)" ? emptyMsg : emptyMsg,
|
|
1899
|
-
inner,
|
|
1900
|
-
);
|
|
1901
|
-
dataLines.push(
|
|
1902
|
-
`${borderSeq}│${RESET} ${padRight(emptyMsg, inner - 2)} ${borderSeq}│${RESET}`,
|
|
1903
|
-
);
|
|
1904
|
-
} else {
|
|
1905
|
-
for (const s of snapshot) {
|
|
1906
|
-
const id = String(s.id ?? "").slice(0, COL_ID);
|
|
1907
|
-
const agent = String(s.agent ?? "unknown").slice(0, COL_AGENT);
|
|
1908
|
-
const host = "local";
|
|
1909
|
-
const state = s.state ?? "init";
|
|
1910
|
-
const healthCell = conductorHealthCell(state);
|
|
1911
|
-
const lastOut = conductorRelTime(s.health?.lastProbeAt ?? null);
|
|
1912
|
-
const restarts = s.restarts ?? 0;
|
|
1913
|
-
// derive "why" from last state transition context
|
|
1914
|
-
const why = s.health?.inputWaitPattern
|
|
1915
|
-
? String(s.health.inputWaitPattern).slice(0, COL_WHY)
|
|
1916
|
-
: "";
|
|
1917
|
-
|
|
1918
|
-
const rowText = buildRow(
|
|
1919
|
-
id,
|
|
1920
|
-
agent,
|
|
1921
|
-
host,
|
|
1922
|
-
healthCell,
|
|
1923
|
-
lastOut,
|
|
1924
|
-
restarts,
|
|
1925
|
-
why,
|
|
1926
|
-
);
|
|
1927
|
-
dataLines.push(`${borderSeq}│${RESET} ${rowText} ${borderSeq}│${RESET}`);
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
|
-
// ── Bottom border ─────────────────────────────────────
|
|
1932
|
-
const botBorder = `${borderSeq}└${"─".repeat(boxWidth)}┘${RESET}`;
|
|
1933
|
-
|
|
1934
|
-
return [topBorder, headerLine, ...dataLines, botBorder];
|
|
1935
|
-
}
|
|
1936
|
-
|
|
1937
|
-
// 하위 호환
|
|
1938
|
-
export { createLogDashboard as createTui };
|
package/hub/team/wt-manager.mjs
CHANGED
|
@@ -231,7 +231,7 @@ export function createWtManager(opts = {}) {
|
|
|
231
231
|
opts.tabCreateDelayMs,
|
|
232
232
|
DEFAULT_TAB_CREATE_DELAY_MS,
|
|
233
233
|
) || DEFAULT_TAB_CREATE_DELAY_MS;
|
|
234
|
-
const
|
|
234
|
+
const waitTimeoutMs =
|
|
235
235
|
resolvePositiveInteger(
|
|
236
236
|
opts.waitTimeoutMs,
|
|
237
237
|
process.env.WTM_WAIT_TIMEOUT_MS,
|
|
@@ -274,7 +274,7 @@ export function createWtManager(opts = {}) {
|
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
async function waitTabReady(title, pidFile) {
|
|
277
|
-
const deadline = now() +
|
|
277
|
+
const deadline = now() + waitTimeoutMs;
|
|
278
278
|
|
|
279
279
|
while (now() <= deadline) {
|
|
280
280
|
if (exists(pidFile)) {
|
package/hub/workers/factory.mjs
CHANGED
|
@@ -1,45 +1,17 @@
|
|
|
1
1
|
// hub/workers/factory.mjs — Worker 생성 팩토리
|
|
2
2
|
//
|
|
3
3
|
// Supported worker types:
|
|
4
|
-
// - 'gemini' → AntigravityRouteWorker (deprecated alias)
|
|
5
|
-
// - 'antigravity' → AntigravityRouteWorker
|
|
6
4
|
// - 'claude' → ClaudeWorker
|
|
7
5
|
// - 'codex' → CodexMcpWorker (default) or CodexAppServerWorker when
|
|
8
6
|
// opts.transport === 'app-server'
|
|
9
7
|
// - 'codex-app-server' → CodexAppServerWorker (explicit alias)
|
|
10
8
|
// - 'delegator' → DelegatorMcpWorker
|
|
11
9
|
//
|
|
12
|
-
// For the codex app-server transport the factory injects a default
|
|
13
|
-
// `publishCallback` that forwards each envelope to `/bridge/publish` via the
|
|
14
|
-
// existing `requestJson` helper. Callers can override by passing their own
|
|
15
|
-
// `publishCallback` or swap the transport with `requestJsonFn`.
|
|
16
|
-
|
|
17
|
-
import { AntigravityRouteWorker } from "./antigravity-route-worker.mjs";
|
|
18
10
|
import { ClaudeWorker } from "./claude-worker.mjs";
|
|
19
11
|
import { CodexAppServerWorker } from "./codex-app-server-worker.mjs";
|
|
20
12
|
|
|
21
13
|
/**
|
|
22
|
-
*
|
|
23
|
-
* `/bridge/publish`. Failures are swallowed so publish pressure never crashes
|
|
24
|
-
* a running worker turn.
|
|
25
|
-
* @param {(path: string, opts?: object) => Promise<unknown>} [requestJsonFn]
|
|
26
|
-
* @returns {(publishMessage: object) => Promise<void>}
|
|
27
|
-
*/
|
|
28
|
-
function defaultPublishCallback(requestJsonFn = null) {
|
|
29
|
-
return async (publishMessage) => {
|
|
30
|
-
try {
|
|
31
|
-
const publishRequestJson =
|
|
32
|
-
requestJsonFn || (await import("@triflux/core/hub/bridge.mjs")).requestJson;
|
|
33
|
-
await publishRequestJson("/bridge/publish", { body: publishMessage });
|
|
34
|
-
} catch {
|
|
35
|
-
// best-effort; publish failures must not crash the worker
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Construct a CodexAppServerWorker with a default publishCallback wired to
|
|
42
|
-
* `requestJson('/bridge/publish', ...)` unless the caller supplied one.
|
|
14
|
+
* 호출자가 지정한 발행 콜백만 연결한다.
|
|
43
15
|
*
|
|
44
16
|
* Issue #95 P1 #4 validation: the app-server transport does not yet implement
|
|
45
17
|
* the server-initiated approval / `tool/requestUserInput` round-trip. Any
|
|
@@ -51,6 +23,7 @@ function defaultPublishCallback(requestJsonFn = null) {
|
|
|
51
23
|
*/
|
|
52
24
|
async function createCodexWorker(opts = {}) {
|
|
53
25
|
const { transport, requestJsonFn, publishCallback, ...rest } = opts;
|
|
26
|
+
void requestJsonFn;
|
|
54
27
|
|
|
55
28
|
if (transport === "app-server") {
|
|
56
29
|
const policy = rest.approvalPolicy;
|
|
@@ -65,9 +38,7 @@ async function createCodexWorker(opts = {}) {
|
|
|
65
38
|
return new CodexAppServerWorker({
|
|
66
39
|
...rest,
|
|
67
40
|
publishCallback:
|
|
68
|
-
typeof publishCallback === "function"
|
|
69
|
-
? publishCallback
|
|
70
|
-
: defaultPublishCallback(requestJsonFn),
|
|
41
|
+
typeof publishCallback === "function" ? publishCallback : null,
|
|
71
42
|
});
|
|
72
43
|
}
|
|
73
44
|
|
|
@@ -77,16 +48,12 @@ async function createCodexWorker(opts = {}) {
|
|
|
77
48
|
}
|
|
78
49
|
|
|
79
50
|
/**
|
|
80
|
-
* @param {'
|
|
51
|
+
* @param {'claude'|'codex'|'codex-app-server'|'delegator'} type
|
|
81
52
|
* @param {object} [opts]
|
|
82
53
|
* @returns {Promise<import('./interface.mjs').IWorker>}
|
|
83
54
|
*/
|
|
84
55
|
export async function createWorker(type, opts = {}) {
|
|
85
56
|
switch (type) {
|
|
86
|
-
case "gemini":
|
|
87
|
-
case "antigravity":
|
|
88
|
-
case "agy":
|
|
89
|
-
return new AntigravityRouteWorker(opts);
|
|
90
57
|
case "claude":
|
|
91
58
|
return new ClaudeWorker(opts);
|
|
92
59
|
case "codex":
|