@triflux/remote 10.50.1 → 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.
Files changed (120) hide show
  1. package/cto/brief.mjs +0 -12
  2. package/cto/collect.mjs +16 -247
  3. package/cto/current.schema.json +4 -20
  4. package/cto/events.mjs +13 -294
  5. package/cto/hygiene.mjs +26 -346
  6. package/cto/lake-root.mjs +114 -16
  7. package/cto/status.mjs +33 -128
  8. package/hub/index.mjs +0 -8
  9. package/hub/store-adapter.mjs +1 -1
  10. package/hub/team/agent-map.json +0 -1
  11. package/hub/team/ansi.mjs +1 -35
  12. package/hub/team/backend.mjs +9 -145
  13. package/hub/team/cli/commands/attach.mjs +1 -17
  14. package/hub/team/cli/commands/control.mjs +12 -38
  15. package/hub/team/cli/commands/debug.mjs +1 -37
  16. package/hub/team/cli/commands/focus.mjs +5 -31
  17. package/hub/team/cli/commands/interrupt.mjs +6 -25
  18. package/hub/team/cli/commands/kill.mjs +1 -30
  19. package/hub/team/cli/commands/list.mjs +0 -16
  20. package/hub/team/cli/commands/send.mjs +6 -26
  21. package/hub/team/cli/commands/start/index.mjs +41 -133
  22. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  23. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  24. package/hub/team/cli/commands/start/start-mux.mjs +0 -3
  25. package/hub/team/cli/commands/status.mjs +2 -57
  26. package/hub/team/cli/commands/stop.mjs +14 -19
  27. package/hub/team/cli/help.mjs +4 -5
  28. package/hub/team/cli/manifest.mjs +5 -1
  29. package/hub/team/cli/render.mjs +0 -12
  30. package/hub/team/cli/services/hub-client.mjs +2 -88
  31. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  32. package/hub/team/handoff.mjs +3 -34
  33. package/hub/team/headless.mjs +14 -755
  34. package/hub/team/orchestrator.mjs +4 -30
  35. package/hub/team/pane.mjs +6 -28
  36. package/hub/team/psmux.mjs +16 -403
  37. package/hub/team/remote-session.mjs +1 -2
  38. package/hub/team/session.mjs +8 -119
  39. package/hub/team/swarm-intent.mjs +0 -198
  40. package/hub/team/terminal-opener.mjs +11 -35
  41. package/hub/team/tui-core.mjs +1 -1
  42. package/hub/team/tui-viewer.mjs +2 -2
  43. package/hub/team/tui.mjs +8 -269
  44. package/hub/team/wt-manager.mjs +2 -2
  45. package/hub/workers/factory.mjs +4 -37
  46. package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
  47. package/package.json +1 -1
  48. package/scripts/lib/agent-route-policy.mjs +162 -14
  49. package/scripts/lib/claudemd-scanner.mjs +2 -199
  50. package/scripts/lib/cli-claude.mjs +0 -2
  51. package/scripts/lib/context.mjs +3 -19
  52. package/scripts/lib/env-probe.mjs +5 -64
  53. package/scripts/lib/gemini-profiles.mjs +2 -69
  54. package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
  55. package/scripts/lib/machine-profile.mjs +3 -17
  56. package/scripts/lib/mcp-filter.mjs +109 -53
  57. package/scripts/lib/mcp-health.mjs +2 -2
  58. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  59. package/scripts/lib/psmux-info.mjs +25 -104
  60. package/scripts/lib/skill-template.mjs +0 -271
  61. package/cto/hygiene-actions.mjs +0 -355
  62. package/cto/hygiene-notify.mjs +0 -170
  63. package/hub/team/build-worker-prompt.mjs +0 -92
  64. package/hub/team/check-mcp-hub.mjs +0 -49
  65. package/hub/team/claude-native-bridge.mjs +0 -987
  66. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  67. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  68. package/hub/team/cli/services/native-control.mjs +0 -145
  69. package/hub/team/codex-review.mjs +0 -520
  70. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  71. package/hub/team/conductor.mjs +0 -1529
  72. package/hub/team/consensus-meta.mjs +0 -176
  73. package/hub/team/cto-pull.mjs +0 -31
  74. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  75. package/hub/team/dashboard.mjs +0 -322
  76. package/hub/team/event-log.mjs +0 -84
  77. package/hub/team/execution-mode.mjs +0 -324
  78. package/hub/team/extract-completion-payload.mjs +0 -110
  79. package/hub/team/headless-bridge-session.mjs +0 -17
  80. package/hub/team/health-probe.mjs +0 -435
  81. package/hub/team/interactive-native-launcher.mjs +0 -119
  82. package/hub/team/interactive-native-worker.mjs +0 -80
  83. package/hub/team/interactive-tui-transport.mjs +0 -479
  84. package/hub/team/launcher-template.mjs +0 -144
  85. package/hub/team/mcp-selector.mjs +0 -145
  86. package/hub/team/native-supervisor.mjs +0 -460
  87. package/hub/team/native.mjs +0 -727
  88. package/hub/team/recovery-store.mjs +0 -149
  89. package/hub/team/remote-probe.mjs +0 -292
  90. package/hub/team/remote-watcher.mjs +0 -506
  91. package/hub/team/runtime-strategy.mjs +0 -200
  92. package/hub/team/schemas/worker-completion.json +0 -39
  93. package/hub/team/sentinel-capture.mjs +0 -127
  94. package/hub/team/swarm-cli.mjs +0 -390
  95. package/hub/team/swarm-hypervisor.mjs +0 -2206
  96. package/hub/team/swarm-locks.mjs +0 -335
  97. package/hub/team/swarm-planner.mjs +0 -371
  98. package/hub/team/swarm-preflight.mjs +0 -366
  99. package/hub/team/swarm-reconciler.mjs +0 -242
  100. package/hub/team/tui-remote-adapter.mjs +0 -377
  101. package/hub/team/worker-completion-validator.mjs +0 -79
  102. package/hub/team/worktree-lifecycle.mjs +0 -639
  103. package/hub/team/wt-templates.json +0 -43
  104. package/hub/workers/antigravity-route-worker.mjs +0 -179
  105. package/hub/workers/gemini-worker.mjs +0 -217
  106. package/scripts/lib/agent-json.mjs +0 -27
  107. package/scripts/lib/async.mjs +0 -174
  108. package/scripts/lib/cli-agy.mjs +0 -85
  109. package/scripts/lib/cli-codex.mjs +0 -62
  110. package/scripts/lib/cli-gemini.mjs +0 -37
  111. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  112. package/scripts/lib/env.mjs +0 -14
  113. package/scripts/lib/hub.mjs +0 -48
  114. package/scripts/lib/pid.mjs +0 -63
  115. package/scripts/lib/quota.mjs +0 -47
  116. package/scripts/lib/skill-state.mjs +0 -220
  117. package/scripts/lib/team.mjs +0 -75
  118. package/scripts/lib/timeout.mjs +0 -66
  119. package/scripts/lib/tmp.mjs +0 -26
  120. package/scripts/lib/toml.mjs +0 -132
@@ -1,4 +1,4 @@
1
- import { attachSession, focusPane, focusWtPane } from "../../session.mjs";
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, YELLOW } from "../../shared.mjs";
3
- import { ok, warn } from "../render.mjs";
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 { nativeRequest } from "../services/native-control.mjs";
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 { closeWtSession, killSession, listSessions } from "../../session.mjs";
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, YELLOW } from "../../shared.mjs";
3
- import { ok, warn } from "../render.mjs";
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 { nativeRequest } from "../services/native-control.mjs";
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
- AMBER,
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
- resolveEffectiveMode,
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
- console.log(`\n ${AMBER}${BOLD}⬡ tfx multi${RESET}\n`);
120
-
121
- // P1b: 워커 수 계산 — 단일 워커 headless에는 Hub 불필요
122
- const workerCount = agents.length;
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
- let hub = null;
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 === "tmux") {
160
- try {
161
- ensureTmuxOrExit();
162
- } catch {
163
- return renderTmuxInstallHelp();
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
- effectiveMode === "in-process"
169
- ? await startInProcessTeam({
170
- sessionId,
171
- task,
172
- lead,
173
- agents,
174
- subtasks,
175
- hubUrl,
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("in-process supervisor 시작 실패");
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
- // --assign 파싱 시 마지막 콜론 뒤를 role로 인식할 알려진 역할/CLI 이름
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. 마지막 콜론 뒤가 KNOWN_ROLES에 있으면 role, 나머지가 prompt
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 (KNOWN_ROLES.has(candidate)) {
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 = []; // --assign "codex:프롬프트:역할" 형식
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 (!NATIVE_BRIDGE_MODES.has(mode)) {
131
+ if (mode !== "agents") {
163
132
  throw new Error(
164
- `unknown native bridge mode: ${mode || ""}; expected roster, agents, interactive-attach, or claude-wrapper`,
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 normalizedTeammateMode = normalizeTeammateMode(teammateMode);
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: taskParts.join(" ").trim(),
173
+ task,
199
174
  assigns,
200
175
  autoAttach,
201
176
  progressive,