@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { attachSession, focusPane
|
|
1
|
+
import { attachSession, focusPane } from "../../session.mjs";
|
|
2
2
|
import { DIM, RESET, WHITE } from "../../shared.mjs";
|
|
3
3
|
import { fail, ok, warn } from "../render.mjs";
|
|
4
4
|
import {
|
|
@@ -7,25 +7,18 @@ import {
|
|
|
7
7
|
wantsWtAttachFallback,
|
|
8
8
|
} from "../services/attach-fallback.mjs";
|
|
9
9
|
import { resolveMember } from "../services/member-selector.mjs";
|
|
10
|
-
import {
|
|
11
|
-
isNativeMode,
|
|
12
|
-
isTeamAlive,
|
|
13
|
-
isWtMode,
|
|
14
|
-
} from "../services/runtime-mode.mjs";
|
|
10
|
+
import { isTeamAlive } from "../services/runtime-mode.mjs";
|
|
15
11
|
import { loadTeamState } from "../services/state-store.mjs";
|
|
16
12
|
|
|
17
13
|
export async function teamFocus(args = []) {
|
|
18
14
|
const state = loadTeamState();
|
|
15
|
+
if (state?.teammateMode === "headless") {
|
|
16
|
+
throw new Error("headless 실행에는 지원하지 않는다");
|
|
17
|
+
}
|
|
19
18
|
if (!state || !isTeamAlive(state)) {
|
|
20
19
|
console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
|
|
21
20
|
return;
|
|
22
21
|
}
|
|
23
|
-
if (isNativeMode(state)) {
|
|
24
|
-
console.log(
|
|
25
|
-
`\n ${DIM}in-process 모드는 focus/attach 개념이 없습니다.${RESET}\n ${DIM}직접 지시: tfx multi send <대상> "메시지"${RESET}\n`,
|
|
26
|
-
);
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
22
|
|
|
30
23
|
const member = resolveMember(state, args[0]);
|
|
31
24
|
if (!member) {
|
|
@@ -35,25 +28,6 @@ export async function teamFocus(args = []) {
|
|
|
35
28
|
return;
|
|
36
29
|
}
|
|
37
30
|
|
|
38
|
-
if (isWtMode(state)) {
|
|
39
|
-
const paneIndex = Number(/^wt:(\d+)$/.exec(member.pane || "")?.[1]);
|
|
40
|
-
if (!Number.isFinite(paneIndex)) {
|
|
41
|
-
console.log(
|
|
42
|
-
`\n ${DIM}wt pane 인덱스 파싱 실패: ${member.pane}${RESET}\n`,
|
|
43
|
-
);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (
|
|
47
|
-
focusWtPane(paneIndex, {
|
|
48
|
-
layout: state?.wt?.layout || state?.layout || "1xN",
|
|
49
|
-
})
|
|
50
|
-
)
|
|
51
|
-
ok(`${member.name} pane 포커스 이동 (wt)`);
|
|
52
|
-
else warn("wt pane 포커스 이동 실패 (WT_SESSION/wt.exe 상태 확인 필요)");
|
|
53
|
-
console.log("");
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
31
|
focusPane(member.pane, { zoom: false });
|
|
58
32
|
try {
|
|
59
33
|
attachSession(state.sessionName);
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { sendKeys } from "../../pane.mjs";
|
|
2
|
-
import { DIM, RESET, WHITE
|
|
3
|
-
import { ok
|
|
2
|
+
import { DIM, RESET, WHITE } from "../../shared.mjs";
|
|
3
|
+
import { ok } from "../render.mjs";
|
|
4
4
|
import { resolveMember } from "../services/member-selector.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
isNativeMode,
|
|
8
|
-
isTeamAlive,
|
|
9
|
-
isWtMode,
|
|
10
|
-
} from "../services/runtime-mode.mjs";
|
|
5
|
+
import { isTeamAlive } from "../services/runtime-mode.mjs";
|
|
11
6
|
import { loadTeamState } from "../services/state-store.mjs";
|
|
12
7
|
|
|
13
8
|
export async function teamInterrupt(args = []) {
|
|
14
9
|
const state = loadTeamState();
|
|
10
|
+
if (state?.teammateMode === "headless") {
|
|
11
|
+
throw new Error("headless 실행에는 지원하지 않는다");
|
|
12
|
+
}
|
|
15
13
|
if (!state || !isTeamAlive(state)) {
|
|
16
14
|
console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
|
|
17
15
|
return;
|
|
@@ -24,23 +22,6 @@ export async function teamInterrupt(args = []) {
|
|
|
24
22
|
);
|
|
25
23
|
return;
|
|
26
24
|
}
|
|
27
|
-
if (isWtMode(state)) {
|
|
28
|
-
console.log(
|
|
29
|
-
`\n ${YELLOW}⚠${RESET} wt 모드에서는 pane stdin 주입이 지원되지 않아 interrupt를 자동 전송할 수 없습니다.\n ${DIM}수동으로 해당 pane에서 Ctrl+C를 입력하세요.${RESET}\n`,
|
|
30
|
-
);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (isNativeMode(state)) {
|
|
35
|
-
const result = await nativeRequest(state, "/interrupt", {
|
|
36
|
-
member: member.name,
|
|
37
|
-
});
|
|
38
|
-
(result?.ok ? ok : warn)(
|
|
39
|
-
`${member.name} ${result?.ok ? "인터럽트 전송" : "인터럽트 실패"}`,
|
|
40
|
-
);
|
|
41
|
-
console.log("");
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
25
|
|
|
45
26
|
sendKeys(member.pane, "C-c");
|
|
46
27
|
ok(`${member.name} 인터럽트 전송`);
|
|
@@ -1,39 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { killSession, listSessions } from "../../session.mjs";
|
|
2
2
|
import { DIM, RESET } from "../../shared.mjs";
|
|
3
3
|
import { ok } from "../render.mjs";
|
|
4
|
-
import { nativeRequest } from "../services/native-control.mjs";
|
|
5
|
-
import {
|
|
6
|
-
isNativeMode,
|
|
7
|
-
isTeamAlive,
|
|
8
|
-
isWtMode,
|
|
9
|
-
} from "../services/runtime-mode.mjs";
|
|
10
4
|
import { clearTeamState, loadTeamState } from "../services/state-store.mjs";
|
|
11
5
|
|
|
12
6
|
export async function teamKill() {
|
|
13
7
|
const state = loadTeamState();
|
|
14
|
-
if (state && isNativeMode(state) && isTeamAlive(state)) {
|
|
15
|
-
await nativeRequest(state, "/stop", {});
|
|
16
|
-
try {
|
|
17
|
-
process.kill(state.native.supervisorPid, "SIGTERM");
|
|
18
|
-
} catch {}
|
|
19
|
-
clearTeamState(state.sessionId);
|
|
20
|
-
ok(`종료: ${state.sessionName}`);
|
|
21
|
-
console.log("");
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (state && isWtMode(state)) {
|
|
25
|
-
const closed = closeWtSession({
|
|
26
|
-
layout: state?.wt?.layout || state?.layout || "1xN",
|
|
27
|
-
paneCount: state?.wt?.paneCount ?? (state.members || []).length,
|
|
28
|
-
});
|
|
29
|
-
clearTeamState(state.sessionId);
|
|
30
|
-
ok(
|
|
31
|
-
`종료: ${state.sessionName}${closed ? ` (${closed} panes closed)` : ""}`,
|
|
32
|
-
);
|
|
33
|
-
console.log("");
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
8
|
const sessions = listSessions();
|
|
38
9
|
if (!sessions.length) {
|
|
39
10
|
console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
|
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
import { listSessions } from "../../session.mjs";
|
|
2
2
|
import { AMBER, BOLD, DIM, GREEN, RESET } from "../../shared.mjs";
|
|
3
|
-
import {
|
|
4
|
-
isNativeMode,
|
|
5
|
-
isTeamAlive,
|
|
6
|
-
isWtMode,
|
|
7
|
-
} from "../services/runtime-mode.mjs";
|
|
8
|
-
import { loadTeamState } from "../services/state-store.mjs";
|
|
9
3
|
|
|
10
4
|
export function teamList() {
|
|
11
|
-
const state = loadTeamState();
|
|
12
|
-
if (state && isTeamAlive(state) && (isNativeMode(state) || isWtMode(state))) {
|
|
13
|
-
console.log(`\n ${AMBER}${BOLD}⬡ 팀 세션 목록${RESET}\n`);
|
|
14
|
-
console.log(
|
|
15
|
-
` ${GREEN}●${RESET} ${state.sessionName} ${DIM}(${isNativeMode(state) ? "in-process" : "wt"})${RESET}`,
|
|
16
|
-
);
|
|
17
|
-
console.log("");
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
5
|
const sessions = listSessions();
|
|
22
6
|
if (!sessions.length) {
|
|
23
7
|
console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { injectPrompt } from "../../pane.mjs";
|
|
2
|
-
import { DIM, RESET, WHITE
|
|
3
|
-
import { ok
|
|
2
|
+
import { DIM, RESET, WHITE } from "../../shared.mjs";
|
|
3
|
+
import { ok } from "../render.mjs";
|
|
4
4
|
import { resolveMember } from "../services/member-selector.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
isNativeMode,
|
|
8
|
-
isTeamAlive,
|
|
9
|
-
isWtMode,
|
|
10
|
-
} from "../services/runtime-mode.mjs";
|
|
5
|
+
import { isTeamAlive } from "../services/runtime-mode.mjs";
|
|
11
6
|
import { loadTeamState } from "../services/state-store.mjs";
|
|
12
7
|
|
|
13
8
|
export async function teamSend(args = []) {
|
|
14
9
|
const state = loadTeamState();
|
|
10
|
+
if (state?.teammateMode === "headless") {
|
|
11
|
+
throw new Error("headless 실행에는 지원하지 않는다");
|
|
12
|
+
}
|
|
15
13
|
if (!state || !isTeamAlive(state)) {
|
|
16
14
|
console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
|
|
17
15
|
return;
|
|
@@ -25,24 +23,6 @@ export async function teamSend(args = []) {
|
|
|
25
23
|
);
|
|
26
24
|
return;
|
|
27
25
|
}
|
|
28
|
-
if (isWtMode(state)) {
|
|
29
|
-
console.log(
|
|
30
|
-
`\n ${YELLOW}⚠${RESET} wt 모드는 pane 프롬프트 자동 주입(send)이 지원되지 않습니다.\n ${DIM}수동 전달: 선택한 pane에 직접 붙여넣으세요.${RESET}\n`,
|
|
31
|
-
);
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (isNativeMode(state)) {
|
|
36
|
-
const result = await nativeRequest(state, "/send", {
|
|
37
|
-
member: member.name,
|
|
38
|
-
text: message,
|
|
39
|
-
});
|
|
40
|
-
(result?.ok ? ok : warn)(
|
|
41
|
-
`${member.name}${result?.ok ? "에 메시지 주입 완료" : " 메시지 주입 실패"}`,
|
|
42
|
-
);
|
|
43
|
-
console.log("");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
26
|
|
|
47
27
|
injectPrompt(member.pane, message);
|
|
48
28
|
ok(`${member.name}에 메시지 주입 완료`);
|
|
@@ -1,29 +1,14 @@
|
|
|
1
1
|
import { decomposeTask } from "../../../orchestrator.mjs";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
BOLD,
|
|
5
|
-
DIM,
|
|
6
|
-
GREEN,
|
|
7
|
-
RED,
|
|
8
|
-
RESET,
|
|
9
|
-
WHITE,
|
|
10
|
-
} from "../../../shared.mjs";
|
|
11
|
-
import { fail, ok, warn } from "../../render.mjs";
|
|
12
|
-
import {
|
|
13
|
-
getDefaultHubUrl,
|
|
14
|
-
getHubInfo,
|
|
15
|
-
startHubDaemon,
|
|
16
|
-
} from "../../services/hub-client.mjs";
|
|
2
|
+
import { AMBER, BOLD, DIM, RESET, WHITE } from "../../../shared.mjs";
|
|
3
|
+
import { fail } from "../../render.mjs";
|
|
17
4
|
import {
|
|
18
5
|
ensureTmuxOrExit,
|
|
19
|
-
|
|
6
|
+
normalizeTeammateMode,
|
|
20
7
|
} from "../../services/runtime-mode.mjs";
|
|
21
8
|
import { saveTeamState } from "../../services/state-store.mjs";
|
|
22
9
|
import { parseTeamArgs } from "./parse-args.mjs";
|
|
23
10
|
import { startHeadlessTeam } from "./start-headless.mjs";
|
|
24
|
-
import { startInProcessTeam } from "./start-in-process.mjs";
|
|
25
11
|
import { startMuxTeam } from "./start-mux.mjs";
|
|
26
|
-
import { startWtTeam } from "./start-wt.mjs";
|
|
27
12
|
|
|
28
13
|
function printStartUsage() {
|
|
29
14
|
console.log(`\n ${AMBER}${BOLD}⬡ tfx multi${RESET}\n`);
|
|
@@ -43,12 +28,6 @@ function printStartUsage() {
|
|
|
43
28
|
console.log(
|
|
44
29
|
` ${WHITE}tfx multi --dashboard-anchor window "작업"${RESET} ${DIM}(dashboard anchor: window|tab, 기본 window)${RESET}`,
|
|
45
30
|
);
|
|
46
|
-
console.log(
|
|
47
|
-
` ${WHITE}tfx multi --teammate-mode wt "작업"${RESET} ${DIM}(Windows Terminal split-pane)${RESET}`,
|
|
48
|
-
);
|
|
49
|
-
console.log(
|
|
50
|
-
` ${WHITE}tfx multi --teammate-mode in-process "작업"${RESET} ${DIM}(mux 불필요)${RESET}\n`,
|
|
51
|
-
);
|
|
52
31
|
}
|
|
53
32
|
|
|
54
33
|
function printWorkerPreview(agents, subtasks) {
|
|
@@ -62,14 +41,6 @@ function printWorkerPreview(agents, subtasks) {
|
|
|
62
41
|
console.log("");
|
|
63
42
|
}
|
|
64
43
|
|
|
65
|
-
function renderTmuxInstallHelp() {
|
|
66
|
-
console.log(`\n ${RED}${BOLD}tmux 미발견${RESET}\n`);
|
|
67
|
-
console.log(" 현재 선택한 모드는 tmux 기반 팀세션이 필요합니다.\n");
|
|
68
|
-
console.log(
|
|
69
|
-
` 설치:\n Windows: ${WHITE}winget install psmux${RESET}\n macOS: ${WHITE}brew install tmux${RESET}\n Linux: ${WHITE}apt install tmux${RESET}\n`,
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
44
|
export { parseTeamArgs };
|
|
74
45
|
|
|
75
46
|
export function resolveTeamWorkers({ agents, task, assigns = [] }) {
|
|
@@ -116,37 +87,14 @@ export async function teamStart(args = []) {
|
|
|
116
87
|
assigns,
|
|
117
88
|
});
|
|
118
89
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const needsHub = workerCount >= 2 || teammateMode !== "headless";
|
|
90
|
+
const effectiveMode = normalizeTeammateMode(teammateMode);
|
|
91
|
+
if (effectiveMode !== "headless") ensureTmuxOrExit();
|
|
92
|
+
const effectiveNativeBridge =
|
|
93
|
+
effectiveMode === "headless" && !nativeBridgeUiOptOut ? true : nativeBridge;
|
|
124
94
|
|
|
125
|
-
|
|
126
|
-
if (needsHub) {
|
|
127
|
-
hub = await getHubInfo();
|
|
128
|
-
if (!hub) {
|
|
129
|
-
process.stdout.write(" Hub 시작 중...");
|
|
130
|
-
try {
|
|
131
|
-
hub = await startHubDaemon();
|
|
132
|
-
} catch (error) {
|
|
133
|
-
if (error?.code === "HUB_SERVER_MISSING")
|
|
134
|
-
fail("hub/server.mjs 없음 — hub 모듈이 설치되지 않음");
|
|
135
|
-
}
|
|
136
|
-
console.log(` ${hub ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`}`);
|
|
137
|
-
if (!hub) warn("Hub 시작 실패 — 수동으로 실행: tfx hub start");
|
|
138
|
-
} else ok(`Hub: ${DIM}${hub.url}${RESET}`);
|
|
139
|
-
} else {
|
|
140
|
-
ok(`Hub: ${DIM}건너뜀 (단일 워커 headless)${RESET}`);
|
|
141
|
-
}
|
|
95
|
+
console.log(`\n ${AMBER}${BOLD}⬡ tfx multi${RESET}\n`);
|
|
142
96
|
|
|
143
97
|
const sessionId = `tfx-multi-${Date.now().toString(36).slice(-4)}${Math.random().toString(36).slice(2, 6)}`;
|
|
144
|
-
const hubUrl = hub?.url || getDefaultHubUrl();
|
|
145
|
-
const { mode: effectiveMode, warnings: modeWarnings } =
|
|
146
|
-
resolveEffectiveMode(teammateMode);
|
|
147
|
-
for (const message of modeWarnings) warn(message);
|
|
148
|
-
const effectiveNativeBridge =
|
|
149
|
-
effectiveMode === "headless" && !nativeBridgeUiOptOut ? true : nativeBridge;
|
|
150
98
|
|
|
151
99
|
console.log(` 세션: ${WHITE}${sessionId}${RESET}`);
|
|
152
100
|
console.log(` 모드: ${effectiveMode}`);
|
|
@@ -156,83 +104,43 @@ export async function teamStart(args = []) {
|
|
|
156
104
|
);
|
|
157
105
|
printWorkerPreview(agents, subtasks);
|
|
158
106
|
|
|
159
|
-
if (effectiveMode === "
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
107
|
+
if (effectiveMode === "headless") {
|
|
108
|
+
return startHeadlessTeam({
|
|
109
|
+
sessionId,
|
|
110
|
+
task,
|
|
111
|
+
lead,
|
|
112
|
+
agents,
|
|
113
|
+
subtasks,
|
|
114
|
+
layout,
|
|
115
|
+
assigns,
|
|
116
|
+
autoAttach,
|
|
117
|
+
progressive,
|
|
118
|
+
timeoutSec,
|
|
119
|
+
verbose,
|
|
120
|
+
dashboard,
|
|
121
|
+
dashboardLayout,
|
|
122
|
+
dashboardSize,
|
|
123
|
+
dashboardAnchor,
|
|
124
|
+
mcpProfile,
|
|
125
|
+
model,
|
|
126
|
+
cwd,
|
|
127
|
+
nativeBridge: effectiveNativeBridge,
|
|
128
|
+
nativeBridgeMode,
|
|
129
|
+
});
|
|
165
130
|
}
|
|
166
131
|
|
|
167
|
-
const state =
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
})
|
|
177
|
-
: effectiveMode === "headless"
|
|
178
|
-
? await startHeadlessTeam({
|
|
179
|
-
sessionId,
|
|
180
|
-
task,
|
|
181
|
-
lead,
|
|
182
|
-
agents,
|
|
183
|
-
subtasks,
|
|
184
|
-
layout,
|
|
185
|
-
assigns,
|
|
186
|
-
autoAttach,
|
|
187
|
-
progressive,
|
|
188
|
-
timeoutSec,
|
|
189
|
-
verbose,
|
|
190
|
-
dashboard,
|
|
191
|
-
dashboardLayout,
|
|
192
|
-
dashboardSize,
|
|
193
|
-
dashboardAnchor,
|
|
194
|
-
mcpProfile,
|
|
195
|
-
model,
|
|
196
|
-
cwd,
|
|
197
|
-
nativeBridge: effectiveNativeBridge,
|
|
198
|
-
nativeBridgeMode,
|
|
199
|
-
})
|
|
200
|
-
: effectiveMode === "wt"
|
|
201
|
-
? await startWtTeam({
|
|
202
|
-
sessionId,
|
|
203
|
-
task,
|
|
204
|
-
lead,
|
|
205
|
-
agents,
|
|
206
|
-
subtasks,
|
|
207
|
-
layout,
|
|
208
|
-
hubUrl,
|
|
209
|
-
})
|
|
210
|
-
: await startMuxTeam({
|
|
211
|
-
sessionId,
|
|
212
|
-
task,
|
|
213
|
-
lead,
|
|
214
|
-
agents,
|
|
215
|
-
subtasks,
|
|
216
|
-
layout,
|
|
217
|
-
hubUrl,
|
|
218
|
-
teammateMode: effectiveMode,
|
|
219
|
-
});
|
|
132
|
+
const state = await startMuxTeam({
|
|
133
|
+
sessionId,
|
|
134
|
+
task,
|
|
135
|
+
lead,
|
|
136
|
+
agents,
|
|
137
|
+
subtasks,
|
|
138
|
+
layout,
|
|
139
|
+
teammateMode: effectiveMode,
|
|
140
|
+
});
|
|
220
141
|
|
|
221
|
-
if (!state) return fail("
|
|
142
|
+
if (!state) return fail("팀 세션 시작 실패");
|
|
222
143
|
state.sessionId = sessionId;
|
|
223
144
|
saveTeamState(state, sessionId);
|
|
224
145
|
if (typeof state.postSave === "function") state.postSave();
|
|
225
|
-
if (effectiveMode === "in-process") {
|
|
226
|
-
ok("네이티브 in-process 팀 시작 완료");
|
|
227
|
-
console.log(` ${DIM}tmux 없이 실행됨 (직접 CLI 프로세스)${RESET}`);
|
|
228
|
-
console.log(` ${DIM}제어: tfx multi send/control/tasks/status${RESET}\n`);
|
|
229
|
-
} else if (effectiveMode === "wt") {
|
|
230
|
-
ok("Windows Terminal wt 팀 시작 완료");
|
|
231
|
-
console.log(
|
|
232
|
-
` ${DIM}현재 pane 기준으로 ${state.layout} 분할 생성됨${RESET}`,
|
|
233
|
-
);
|
|
234
|
-
console.log(
|
|
235
|
-
` ${DIM}wt 모드는 자동 프롬프트 주입/Hub direct 제어(send/control)가 제한됩니다.${RESET}\n`,
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
146
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
1
2
|
import { resolve } from "node:path";
|
|
2
3
|
import { parseDashboardAnchor } from "../../../dashboard-anchor.mjs";
|
|
3
4
|
import { parseDashboardLayout } from "../../../dashboard-layout.mjs";
|
|
@@ -6,35 +7,7 @@ import {
|
|
|
6
7
|
normalizeTeammateMode,
|
|
7
8
|
} from "../../services/runtime-mode.mjs";
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
const KNOWN_ROLES = new Set([
|
|
11
|
-
"codex",
|
|
12
|
-
"antigravity",
|
|
13
|
-
"agy",
|
|
14
|
-
"gemini",
|
|
15
|
-
"claude",
|
|
16
|
-
"executor",
|
|
17
|
-
"architect",
|
|
18
|
-
"planner",
|
|
19
|
-
"analyst",
|
|
20
|
-
"critic",
|
|
21
|
-
"debugger",
|
|
22
|
-
"verifier",
|
|
23
|
-
"code-reviewer",
|
|
24
|
-
"security-reviewer",
|
|
25
|
-
"test-engineer",
|
|
26
|
-
"designer",
|
|
27
|
-
"writer",
|
|
28
|
-
"researcher",
|
|
29
|
-
"scientist",
|
|
30
|
-
]);
|
|
31
|
-
|
|
32
|
-
const NATIVE_BRIDGE_MODES = new Set([
|
|
33
|
-
"roster",
|
|
34
|
-
"agents",
|
|
35
|
-
"interactive-attach",
|
|
36
|
-
"claude-wrapper",
|
|
37
|
-
]);
|
|
10
|
+
const AGENT_TO_CLI = createRequire(import.meta.url)("../../../agent-map.json");
|
|
38
11
|
|
|
39
12
|
/**
|
|
40
13
|
* --assign "cli:prompt:role" 형식을 콜론-안전하게 파싱한다.
|
|
@@ -42,7 +15,7 @@ const NATIVE_BRIDGE_MODES = new Set([
|
|
|
42
15
|
*
|
|
43
16
|
* 규칙:
|
|
44
17
|
* 1. 첫 번째 콜론 앞 = CLI 이름
|
|
45
|
-
* 2. 마지막 콜론 뒤가
|
|
18
|
+
* 2. 마지막 콜론 뒤가 agent-map.json에 있으면 role, 나머지가 prompt
|
|
46
19
|
* 3. 그 외에는 첫 콜론 뒤 전체가 prompt, role은 빈 문자열
|
|
47
20
|
*/
|
|
48
21
|
function parseAssignValue(raw) {
|
|
@@ -58,7 +31,7 @@ function parseAssignValue(raw) {
|
|
|
58
31
|
.slice(lastColon + 1)
|
|
59
32
|
.trim()
|
|
60
33
|
.toLowerCase();
|
|
61
|
-
if (
|
|
34
|
+
if (Object.hasOwn(AGENT_TO_CLI, candidate)) {
|
|
62
35
|
return { cli, prompt: rest.slice(0, lastColon).trim(), role: candidate };
|
|
63
36
|
}
|
|
64
37
|
}
|
|
@@ -72,7 +45,7 @@ export function parseTeamArgs(args = []) {
|
|
|
72
45
|
let layout = "2x2";
|
|
73
46
|
let teammateMode = "auto";
|
|
74
47
|
const taskParts = [];
|
|
75
|
-
const assigns = [];
|
|
48
|
+
const assigns = [];
|
|
76
49
|
let autoAttach = true;
|
|
77
50
|
let progressive = true;
|
|
78
51
|
let timeoutSec = 0;
|
|
@@ -109,14 +82,10 @@ export function parseTeamArgs(args = []) {
|
|
|
109
82
|
} else if (current === "--assign" && args[index + 1]) {
|
|
110
83
|
const parsed = parseAssignValue(args[++index]);
|
|
111
84
|
if (parsed) assigns.push(parsed);
|
|
112
|
-
} else if (current === "--auto-attach") {
|
|
113
|
-
autoAttach = true;
|
|
114
85
|
} else if (current === "--no-auto-attach") {
|
|
115
86
|
autoAttach = false;
|
|
116
87
|
} else if (current === "--verbose") {
|
|
117
88
|
verbose = true;
|
|
118
|
-
} else if (current === "--dashboard") {
|
|
119
|
-
dashboard = true;
|
|
120
89
|
} else if (current === "--no-dashboard") {
|
|
121
90
|
dashboard = false;
|
|
122
91
|
} else if (current === "--dashboard-layout" && args[index + 1]) {
|
|
@@ -159,9 +128,9 @@ export function parseTeamArgs(args = []) {
|
|
|
159
128
|
nativeBridgeUiOptOut = true;
|
|
160
129
|
} else if (current === "--native-bridge-mode") {
|
|
161
130
|
const mode = args[++index];
|
|
162
|
-
if (
|
|
131
|
+
if (mode !== "agents") {
|
|
163
132
|
throw new Error(
|
|
164
|
-
`unknown native bridge mode: ${mode || ""}; expected
|
|
133
|
+
`unknown native bridge mode: ${mode || ""}; expected agents`,
|
|
165
134
|
);
|
|
166
135
|
}
|
|
167
136
|
nativeBridge = true;
|
|
@@ -174,6 +143,8 @@ export function parseTeamArgs(args = []) {
|
|
|
174
143
|
p = p[1].toUpperCase() + ":" + p.slice(2);
|
|
175
144
|
}
|
|
176
145
|
cwd = resolve(p);
|
|
146
|
+
} else if (current === "--auto-attach" || current === "--dashboard") {
|
|
147
|
+
// 이전 설치 스킬이 넘기는 기본값 플래그는 무시한다.
|
|
177
148
|
} else if (current.startsWith("-")) {
|
|
178
149
|
console.warn(` ⚠ 미인식 플래그 무시: ${current}`);
|
|
179
150
|
} else {
|
|
@@ -181,7 +152,11 @@ export function parseTeamArgs(args = []) {
|
|
|
181
152
|
}
|
|
182
153
|
}
|
|
183
154
|
|
|
184
|
-
const
|
|
155
|
+
const task = taskParts.join(" ").trim();
|
|
156
|
+
const normalizedTeammateMode =
|
|
157
|
+
task || assigns.length > 0
|
|
158
|
+
? normalizeTeammateMode(teammateMode)
|
|
159
|
+
: teammateMode;
|
|
185
160
|
if (
|
|
186
161
|
!nativeBridgeExplicit &&
|
|
187
162
|
!nativeBridgeUiOptOut &&
|
|
@@ -195,7 +170,7 @@ export function parseTeamArgs(args = []) {
|
|
|
195
170
|
lead,
|
|
196
171
|
layout: normalizeLayout(layout),
|
|
197
172
|
teammateMode: normalizedTeammateMode,
|
|
198
|
-
task
|
|
173
|
+
task,
|
|
199
174
|
assigns,
|
|
200
175
|
autoAttach,
|
|
201
176
|
progressive,
|