triflux 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.
Files changed (166) hide show
  1. package/CLAUDE.md +41 -33
  2. package/README.ko.md +27 -20
  3. package/README.md +26 -19
  4. package/bin/triflux.mjs +22 -393
  5. package/cto/brief.mjs +0 -12
  6. package/cto/collect.mjs +0 -73
  7. package/cto/current.schema.json +0 -4
  8. package/cto/status.mjs +2 -50
  9. package/hooks/agy-session-hook.mjs +11 -56
  10. package/hooks/codex-session-hook.mjs +11 -101
  11. package/hub/bridge.mjs +1 -79
  12. package/hub/cli-adapter-base.mjs +12 -90
  13. package/hub/codex-adapter.mjs +0 -1
  14. package/hub/codex-preflight.mjs +5 -28
  15. package/hub/lib/known-errors.json +2 -2
  16. package/hub/lib/process-utils.mjs +0 -123
  17. package/hub/lib/spawn-trace.mjs +3 -2
  18. package/hub/lib/timeout-defaults.mjs +0 -1
  19. package/hub/role-contract.mjs +0 -2
  20. package/hub/team/agent-map.json +0 -1
  21. package/hub/team/ansi.mjs +1 -35
  22. package/hub/team/backend.mjs +9 -145
  23. package/hub/team/cli/commands/attach.mjs +1 -17
  24. package/hub/team/cli/commands/control.mjs +12 -38
  25. package/hub/team/cli/commands/debug.mjs +1 -37
  26. package/hub/team/cli/commands/focus.mjs +5 -31
  27. package/hub/team/cli/commands/interrupt.mjs +6 -25
  28. package/hub/team/cli/commands/kill.mjs +1 -30
  29. package/hub/team/cli/commands/list.mjs +0 -16
  30. package/hub/team/cli/commands/send.mjs +6 -26
  31. package/hub/team/cli/commands/start/index.mjs +41 -133
  32. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  33. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  34. package/hub/team/cli/commands/start/start-mux.mjs +0 -3
  35. package/hub/team/cli/commands/status.mjs +2 -57
  36. package/hub/team/cli/commands/stop.mjs +14 -19
  37. package/hub/team/cli/help.mjs +4 -5
  38. package/hub/team/cli/manifest.mjs +5 -1
  39. package/hub/team/cli/render.mjs +0 -12
  40. package/hub/team/cli/services/hub-client.mjs +2 -88
  41. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  42. package/hub/team/handoff.mjs +3 -34
  43. package/hub/team/headless.mjs +13 -754
  44. package/hub/team/orchestrator.mjs +4 -30
  45. package/hub/team/pane.mjs +6 -28
  46. package/hub/team/psmux.mjs +0 -1
  47. package/hub/team/remote-session.mjs +1 -2
  48. package/hub/team/session.mjs +7 -91
  49. package/hub/team/swarm-intent.mjs +0 -198
  50. package/hub/team/tui-core.mjs +1 -1
  51. package/hub/team/tui-viewer.mjs +2 -2
  52. package/hub/team/tui.mjs +8 -269
  53. package/hub/team/wt-manager.mjs +2 -2
  54. package/hub/workers/factory.mjs +4 -37
  55. package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
  56. package/hud/cli-policy.mjs +0 -22
  57. package/hud/constants.mjs +11 -26
  58. package/hud/hud-qos-status.mjs +23 -51
  59. package/hud/providers/gemini.mjs +105 -20
  60. package/hud/renderers.mjs +50 -104
  61. package/hud/utils.mjs +2 -2
  62. package/package.json +6 -3
  63. package/scripts/__tests__/spawn-trace.test.mjs +16 -0
  64. package/scripts/cache-warmup.mjs +6 -34
  65. package/scripts/claude-login-detect.mjs +0 -1
  66. package/scripts/claudemd-sync.mjs +1 -28
  67. package/scripts/completions/tfx.bash +3 -12
  68. package/scripts/completions/tfx.fish +3 -6
  69. package/scripts/completions/tfx.zsh +4 -13
  70. package/scripts/lib/agent-route-policy.mjs +162 -14
  71. package/scripts/lib/claudemd-scanner.mjs +2 -199
  72. package/scripts/lib/cli-claude.mjs +0 -2
  73. package/scripts/lib/context.mjs +3 -19
  74. package/scripts/lib/env-probe.mjs +5 -64
  75. package/scripts/lib/gemini-profiles.mjs +2 -69
  76. package/scripts/lib/machine-profile.mjs +3 -17
  77. package/scripts/lib/mcp-filter.mjs +109 -53
  78. package/scripts/lib/mcp-health.mjs +2 -2
  79. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  80. package/scripts/lib/psmux-info.mjs +11 -59
  81. package/scripts/lib/session-presence.mjs +1 -1
  82. package/scripts/lib/skill-template.mjs +0 -245
  83. package/scripts/pack.mjs +3 -26
  84. package/scripts/preflight-cache.mjs +5 -18
  85. package/scripts/release/check-packages-mirror.mjs +0 -1
  86. package/scripts/release/version-manifest.json +9 -1
  87. package/scripts/setup.mjs +69 -2
  88. package/scripts/tfx-route-post.mjs +5 -61
  89. package/scripts/tfx-route-worker.mjs +4 -79
  90. package/scripts/tfx-route.sh +161 -1427
  91. package/skills/tfx-auto/SKILL.md +122 -740
  92. package/skills/tfx-auto/references/consensus-schema.md +161 -0
  93. package/skills/tfx-auto/references/tmux-observation.md +97 -0
  94. package/skills/tfx-remote/SKILL.md +24 -87
  95. package/skills/tfx-research/SKILL.md +11 -11
  96. package/skills/tfx-review/SKILL.md +33 -35
  97. package/skills/tfx-ship/SKILL.md +6 -27
  98. package/skills/tfx-wt/SKILL.md +34 -68
  99. package/config/routing-policy.json +0 -124
  100. package/docs/assets/consensus-flow.svg +0 -125
  101. package/docs/assets/deep-vs-light.svg +0 -193
  102. package/docs/assets/demo-dark.gif +0 -0
  103. package/docs/assets/demo-light.gif +0 -0
  104. package/docs/assets/demo-psmux.gif +0 -0
  105. package/hub/dynamic-routing-engine.mjs +0 -511
  106. package/hub/lib/risk-tier.mjs +0 -53
  107. package/hub/lib/ssh-command.mjs +0 -231
  108. package/hub/lib/staged-file-detect.mjs +0 -43
  109. package/hub/lib/tfx-route-args.mjs +0 -353
  110. package/hub/routing-snapshot.mjs +0 -261
  111. package/hub/team/build-worker-prompt.mjs +0 -92
  112. package/hub/team/check-mcp-hub.mjs +0 -49
  113. package/hub/team/claude-native-bridge.mjs +0 -987
  114. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  115. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  116. package/hub/team/cli/services/native-control.mjs +0 -145
  117. package/hub/team/codex-review.mjs +0 -520
  118. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  119. package/hub/team/conductor.mjs +0 -1529
  120. package/hub/team/consensus-meta.mjs +0 -176
  121. package/hub/team/cto-pull.mjs +0 -31
  122. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  123. package/hub/team/dashboard.mjs +0 -322
  124. package/hub/team/event-log.mjs +0 -84
  125. package/hub/team/execution-mode.mjs +0 -324
  126. package/hub/team/extract-completion-payload.mjs +0 -110
  127. package/hub/team/headless-bridge-session.mjs +0 -17
  128. package/hub/team/health-probe.mjs +0 -435
  129. package/hub/team/interactive-native-launcher.mjs +0 -119
  130. package/hub/team/interactive-native-worker.mjs +0 -80
  131. package/hub/team/interactive-tui-transport.mjs +0 -479
  132. package/hub/team/launcher-template.mjs +0 -144
  133. package/hub/team/mcp-selector.mjs +0 -145
  134. package/hub/team/native-supervisor.mjs +0 -460
  135. package/hub/team/native.mjs +0 -727
  136. package/hub/team/recovery-store.mjs +0 -149
  137. package/hub/team/remote-probe.mjs +0 -292
  138. package/hub/team/remote-watcher.mjs +0 -506
  139. package/hub/team/runtime-strategy.mjs +0 -200
  140. package/hub/team/schemas/worker-completion.json +0 -39
  141. package/hub/team/sentinel-capture.mjs +0 -127
  142. package/hub/team/swarm-cli.mjs +0 -390
  143. package/hub/team/swarm-hypervisor.mjs +0 -2206
  144. package/hub/team/swarm-locks.mjs +0 -335
  145. package/hub/team/swarm-planner.mjs +0 -371
  146. package/hub/team/swarm-preflight.mjs +0 -366
  147. package/hub/team/swarm-reconciler.mjs +0 -242
  148. package/hub/team/tui-remote-adapter.mjs +0 -377
  149. package/hub/team/worker-completion-validator.mjs +0 -79
  150. package/hub/team/worktree-lifecycle.mjs +0 -639
  151. package/hub/team/wt-templates.json +0 -43
  152. package/hub/workers/antigravity-route-worker.mjs +0 -179
  153. package/mesh/index.mjs +0 -69
  154. package/mesh/mesh-budget.mjs +0 -137
  155. package/mesh/mesh-heartbeat.mjs +0 -100
  156. package/mesh/mesh-protocol.mjs +0 -96
  157. package/mesh/mesh-queue.mjs +0 -163
  158. package/mesh/mesh-registry.mjs +0 -78
  159. package/mesh/mesh-router.mjs +0 -77
  160. package/scripts/__tests__/skill-surface.test.mjs +0 -93
  161. package/scripts/demo.mjs +0 -197
  162. package/scripts/doctor-dynamic-routing.mjs +0 -87
  163. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  164. package/skills/_templates/base.md +0 -4
  165. package/skills/_templates/deep.md +0 -6
  166. package/skills/shared/telemetry-segment.md +0 -6
package/bin/triflux.mjs CHANGED
@@ -3,7 +3,6 @@ import { setTimeout as delay } from "node:timers/promises";
3
3
  import { execFileSync, execSync, spawn } from "child_process";
4
4
  // triflux CLI — setup, doctor, version
5
5
  import {
6
- appendFileSync,
7
6
  chmodSync,
8
7
  closeSync,
9
8
  copyFileSync,
@@ -28,10 +27,6 @@ import {
28
27
  checkNetworkAvailability,
29
28
  validateRuntimeCachePaths,
30
29
  } from "../hub/lib/cache-guard.mjs";
31
- import {
32
- decideDispatchMode,
33
- parseArgs as parseRouteArgs,
34
- } from "../hub/lib/tfx-route-args.mjs";
35
30
  import { getPipelineStateDbPath } from "../hub/pipeline/state.mjs";
36
31
  import { getVersionHash } from "../hub/state.mjs";
37
32
  import {
@@ -71,6 +66,7 @@ import {
71
66
  buildWindowsHubAutostartCommand,
72
67
  ensureCodexHubServerConfig,
73
68
  ensureCodexProfiles,
69
+ ensureTrifluxMods,
74
70
  getVersion,
75
71
  getWindowsHubAutostartStatus,
76
72
  isLocalDevSkillDir,
@@ -108,10 +104,8 @@ const GREEN_BRIGHT = "\x1b[38;5;82m";
108
104
  const RED_BRIGHT = "\x1b[38;5;196m";
109
105
 
110
106
  // ── 브랜드 요소 ──
111
- const _BRAND = `${AMBER}${BOLD}triflux${RESET}`;
112
107
  const VER = `${DIM}v${PKG.version}${RESET}`;
113
108
  const LINE = `${GRAY}${"─".repeat(48)}${RESET}`;
114
- const _DOT = `${GRAY}·${RESET}`;
115
109
  const STALE_TEAM_MAX_AGE_SEC = 3600;
116
110
  const DEFAULT_TMUX_CLEANUP_PREFIX = "tfx-*";
117
111
  const DEFAULT_TMUX_CLEANUP_AGE_MIN = 60;
@@ -119,7 +113,6 @@ const ANSI_PATTERN = /\x1B\[[0-?]*[ -/]*[@-~]/g;
119
113
  const HUB_DEFAULT_PORT = 27888;
120
114
  const DOCTOR_HUB_PID_FILE = join(CLAUDE_DIR, "cache", "tfx-hub", "hub.pid");
121
115
 
122
- const _EXIT_SUCCESS = 0;
123
116
  const EXIT_ERROR = 1;
124
117
  const EXIT_ARG_ERROR = 2;
125
118
  const EXIT_CLI_MISSING = 3;
@@ -131,43 +124,15 @@ const JSON_OUTPUT = RAW_ARGS.includes("--json");
131
124
  const NORMALIZED_ARGS = RAW_ARGS.filter((arg) => arg !== "--json");
132
125
 
133
126
  const CLI_COMMAND_SCHEMAS = Object.freeze({
134
- auto: {
135
- usage:
136
- "tfx auto [--cli auto|codex|antigravity|claude] [--mode quick|deep|consensus|live] [--rounds N] [--parallel 1|N|swarm] [--json]",
137
- description:
138
- "tfx-auto 라우팅 결정을 CLI에서 미리보기/직렬화 (실행 skill front door와 같은 flag surface)",
127
+ setup: {
128
+ usage: "tfx setup [--dry-run] [--enable-hub-autostart] [--mods]",
129
+ description: "파일 동기화 + HUD/MCP 설정",
139
130
  options: [
140
131
  {
141
- name: "--cli <name>",
142
- type: "string",
143
- description: "실행 lane 강제: auto|codex|antigravity|claude",
144
- },
145
- {
146
- name: "--mode <name>",
147
- type: "string",
148
- description: "라우팅 모드: quick|deep|consensus|live",
149
- },
150
- {
151
- name: "--rounds <N>",
152
- type: "number",
153
- description: "live peer 왕복 횟수 (기본 4, --mode live 전용)",
154
- },
155
- {
156
- name: "--parallel <1|N|swarm>",
157
- type: "string",
158
- description: "단일/로컬 병렬/PRD swarm 라우팅 힌트",
159
- },
160
- {
161
- name: "--json",
132
+ name: "--mods",
162
133
  type: "boolean",
163
- description: "parse 결과와 dispatch 결정을 JSON으로 출력",
134
+ description: "Claude Code mods 설치 (2.1.287 이상)",
164
135
  },
165
- ],
166
- },
167
- setup: {
168
- usage: "tfx setup [--dry-run] [--enable-hub-autostart]",
169
- description: "파일 동기화 + HUD/MCP 설정",
170
- options: [
171
136
  {
172
137
  name: "--dry-run",
173
138
  type: "boolean",
@@ -188,7 +153,7 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
188
153
  },
189
154
  doctor: {
190
155
  usage:
191
- "tfx doctor [--fix] [--reset] [--audit] [--diagnose] [--purge-logs] [--dynamic-routing] [--cleanup-stale-hubs --dry-run|--apply] [--cleanup-stale-tmux --prefix tfx-* --age-min N --dry-run|--apply] [--json]",
156
+ "tfx doctor [--fix] [--reset] [--audit] [--diagnose] [--purge-logs] [--cleanup-stale-hubs --dry-run|--apply] [--cleanup-stale-tmux --prefix tfx-* --age-min N --dry-run|--apply] [--json]",
192
157
  description: "설치 상태 진단 및 자동 복구",
193
158
  options: [
194
159
  {
@@ -218,12 +183,6 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
218
183
  description:
219
184
  "--fix 와 함께 사용. cli-issues.jsonl 에서 7일 초과 항목 물리 삭제 (#144)",
220
185
  },
221
- {
222
- name: "--dynamic-routing",
223
- type: "boolean",
224
- description:
225
- "Phase 1 dynamic routing 상태 진단 (env / policy / snapshot cache / preview decision)",
226
- },
227
186
  {
228
187
  name: "--cleanup-stale-hubs",
229
188
  type: "boolean",
@@ -397,46 +356,6 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
397
356
  },
398
357
  ],
399
358
  },
400
- swarm: {
401
- usage:
402
- "tfx swarm [run|preflight] <prd-path> [--dry-run|--json|--filter <shard>]",
403
- description: "PRD 기반 멀티모델 x 멀티기기 스웜 실행 (#93)",
404
- subcommands: {
405
- run: "tfx swarm run <prd-path> — verb 명시 실행 (기본 경로와 동일)",
406
- preflight:
407
- "tfx swarm preflight <prd-path> [--json] — 실행 전 go/no-go 리포트 출력",
408
- plan: "tfx swarm plan <prd-path> [--json] — 실행 없이 계획만 출력",
409
- list: "tfx swarm list [--json] — 활성 스웜 세션 조회 (synapse status)",
410
- status: "tfx swarm status [--json] — list alias",
411
- },
412
- options: [
413
- {
414
- name: "--dry-run",
415
- type: "boolean",
416
- description: "PRD 분석만 수행, shard를 실행하지 않음",
417
- },
418
- {
419
- name: "--json",
420
- type: "boolean",
421
- description: "구조화된 JSON 출력",
422
- },
423
- {
424
- name: "--filter",
425
- type: "string",
426
- description: "특정 shard만 실행 (이름 매칭)",
427
- },
428
- {
429
- name: "--max-restarts",
430
- type: "number",
431
- description: "shard별 최대 재시작 횟수 (기본 2)",
432
- },
433
- {
434
- name: "--logs-dir",
435
- type: "string",
436
- description: "이벤트 로그 출력 디렉토리 오버라이드",
437
- },
438
- ],
439
- },
440
359
  why: {
441
360
  usage: "tfx why <path> [--json]",
442
361
  description: "해당 경로의 마지막 커밋에서 X-Intent 트레일러 추출",
@@ -491,9 +410,9 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
491
410
  description: "멀티-CLI 팀 모드",
492
411
  options: [
493
412
  {
494
- name: "--dashboard",
495
- type: "boolean",
496
- description: "headless dashboard viewer 표시 (기본값: 켜짐)",
413
+ name: "--teammate-mode",
414
+ type: "string",
415
+ description: "실행 모드: auto|headless|tmux|psmux (Windows)",
497
416
  },
498
417
  {
499
418
  name: "--no-dashboard",
@@ -574,33 +493,6 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
574
493
  },
575
494
  ],
576
495
  },
577
- review: {
578
- usage:
579
- "tfx review [ref] [--base <ref>] [--timeout <seconds>] [--shard off|per-file] [--json]",
580
- description: "Codex 기반 git diff review 실행",
581
- options: [
582
- {
583
- name: "--base <ref>",
584
- type: "string",
585
- description: "비교 기준 ref",
586
- },
587
- {
588
- name: "--timeout <seconds>",
589
- type: "number",
590
- description: "review 실행 timeout (기본 180)",
591
- },
592
- {
593
- name: "--shard <mode>",
594
- type: "string",
595
- description: "off 또는 per-file",
596
- },
597
- {
598
- name: "--json",
599
- type: "boolean",
600
- description: "review 결과 JSON 출력",
601
- },
602
- ],
603
- },
604
496
  monitor: {
605
497
  usage: "tfx monitor",
606
498
  description: "터미널 TUI 모니터 실행",
@@ -2000,6 +1892,7 @@ function cmdSetup(options = {}) {
2000
1892
  fromUpdate = false,
2001
1893
  overrideVersion,
2002
1894
  enableHubAutostart = false,
1895
+ mods = false,
2003
1896
  } = options;
2004
1897
  if (dryRun) {
2005
1898
  printJson(buildSetupDryRunPlan());
@@ -2026,6 +1919,7 @@ function cmdSetup(options = {}) {
2026
1919
  syncFile(target.src, target.dst, target.label);
2027
1920
  }
2028
1921
  reportSkillSync();
1922
+ ensureTrifluxMods({ install: mods, log: console.log, warn });
2029
1923
 
2030
1924
  // ── psmux 기본 셸 자동 수정 (cmd.exe → PowerShell) ──
2031
1925
  if (process.platform === "win32" && which("psmux")) {
@@ -3952,9 +3846,7 @@ async function cmdDoctor(options = {}) {
3952
3846
  }
3953
3847
 
3954
3848
  // ── Codex Config Health (BUG-H #132) ──
3955
- // _codex_config_swap 의 restore 가 Windows lock/ACL 로 실패하면
3956
- // ~/.codex/config.toml.pre-exec 가 남아 [mcp_servers.*] 섹션이 영구 손실된다.
3957
- // orphan backup 을 감지하고 --fix 로 자동 복원한다.
3849
+ // 이전 버전의 swap이 남긴 백업을 감지하고 --fix로 복원한다.
3958
3850
  section("Codex Config Health");
3959
3851
  {
3960
3852
  const codexConfig = join(CODEX_DIR, "config.toml");
@@ -4404,72 +4296,21 @@ async function cmdUpdate(args = []) {
4404
4296
  console.log(`${GREEN}${BOLD}✓ 업데이트 완료${RESET}\n`);
4405
4297
  }
4406
4298
 
4407
- function readPackagedSkillMetadata(skillName) {
4408
- const skillPath = join(PKG_ROOT, "skills", skillName, "SKILL.md");
4409
- if (!existsSync(skillPath)) return null;
4410
- const metadata = { name: skillName, deprecated: false, supersededBy: null };
4411
- let inFrontmatter = false;
4412
- for (const line of readFileSync(skillPath, "utf8").split(/\r?\n/)) {
4413
- if (line.trim() === "---") {
4414
- if (!inFrontmatter) {
4415
- inFrontmatter = true;
4416
- continue;
4417
- }
4418
- break;
4419
- }
4420
- if (!inFrontmatter) continue;
4421
- const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
4422
- if (!match) continue;
4423
- const [, key, rawValue] = match;
4424
- const value = rawValue.trim().replace(/^["']|["']$/g, "");
4425
- if (key === "deprecated") metadata.deprecated = value === "true";
4426
- if (key === "superseded-by") metadata.supersededBy = value || null;
4427
- }
4428
- return metadata;
4429
- }
4430
-
4431
- function listDeprecatedPackagedSkillAliases(pluginSkills, installedSkills) {
4432
- if (!existsSync(pluginSkills)) return [];
4433
- return readdirSync(pluginSkills)
4434
- .sort()
4435
- .map((name) => readPackagedSkillMetadata(name))
4436
- .filter((metadata) => metadata?.deprecated)
4437
- .map((metadata) => ({
4438
- alias: metadata.name,
4439
- source: metadata.supersededBy || "deprecated",
4440
- installed: existsSync(join(installedSkills, metadata.name, "SKILL.md")),
4441
- deprecated: true,
4442
- }));
4443
- }
4444
-
4445
4299
  function cmdList(options = {}) {
4446
4300
  const { json = false } = options;
4447
4301
  const pluginSkills = join(PKG_ROOT, "skills");
4448
4302
  const installedSkills = join(CLAUDE_DIR, "skills");
4449
4303
  const packageSkills = [];
4450
4304
  const userSkills = [];
4451
- const skillAliases = listDeprecatedPackagedSkillAliases(
4452
- pluginSkills,
4453
- installedSkills,
4454
- );
4455
- const aliasNames = new Set([
4456
- ...SKILL_ALIASES.map(({ alias }) => alias),
4457
- ...skillAliases.map(({ alias }) => alias),
4458
- ]);
4459
4305
 
4460
4306
  if (existsSync(pluginSkills)) {
4461
4307
  for (const name of readdirSync(pluginSkills).sort()) {
4462
4308
  const src = join(pluginSkills, name, "SKILL.md");
4463
4309
  if (!existsSync(src)) continue;
4464
- const metadata = readPackagedSkillMetadata(name);
4465
4310
  const dst = join(installedSkills, name, "SKILL.md");
4466
4311
  packageSkills.push({
4467
4312
  name,
4468
4313
  installed: existsSync(dst),
4469
- ...(metadata?.deprecated ? { deprecated: true } : {}),
4470
- ...(metadata?.supersededBy
4471
- ? { superseded_by: metadata.supersededBy }
4472
- : {}),
4473
4314
  });
4474
4315
  }
4475
4316
  }
@@ -4479,7 +4320,7 @@ function cmdList(options = {}) {
4479
4320
  );
4480
4321
  if (existsSync(installedSkills)) {
4481
4322
  for (const name of readdirSync(installedSkills).sort()) {
4482
- if (pkgNames.has(name) || aliasNames.has(name)) continue;
4323
+ if (pkgNames.has(name)) continue;
4483
4324
  const skill = join(installedSkills, name, "SKILL.md");
4484
4325
  if (!existsSync(skill)) continue;
4485
4326
  userSkills.push(name);
@@ -4489,7 +4330,6 @@ function cmdList(options = {}) {
4489
4330
  if (json) {
4490
4331
  printJson({
4491
4332
  package_skills: packageSkills,
4492
- skill_aliases: skillAliases,
4493
4333
  user_skills: userSkills,
4494
4334
  install_path: installedSkills,
4495
4335
  });
@@ -4516,19 +4356,6 @@ function cmdList(options = {}) {
4516
4356
  }
4517
4357
  if (userSkills.length === 0) console.log(` ${GRAY}없음${RESET}`);
4518
4358
 
4519
- if (skillAliases.length > 0) {
4520
- section("호환 alias");
4521
- for (const entry of skillAliases) {
4522
- const icon = entry.installed
4523
- ? `${GREEN_BRIGHT}↳${RESET}`
4524
- : `${RED_BRIGHT}↳${RESET}`;
4525
- const status = entry.installed ? "" : ` ${GRAY}(미설치)${RESET}`;
4526
- console.log(
4527
- ` ${icon} ${BOLD}${entry.alias}${RESET} ${GRAY}→ ${entry.source}${RESET}${entry.deprecated ? ` ${YELLOW}(deprecated)${RESET}` : ""}${status}`,
4528
- );
4529
- }
4530
- }
4531
-
4532
4359
  console.log(`\n ${LINE}`);
4533
4360
  console.log(` ${GRAY}${installedSkills}${RESET}\n`);
4534
4361
  }
@@ -5021,11 +4848,11 @@ ${updateNotice}
5021
4848
 
5022
4849
  ${WHITE_BRIGHT}tfx setup${RESET} ${GRAY}파일 동기화 + HUD 설정${RESET}
5023
4850
  ${DIM} --dry-run${RESET} ${GRAY}변경 예정 작업을 JSON으로 미리보기${RESET}
4851
+ ${DIM} --mods${RESET} ${GRAY}Claude Code mods 설치 (2.1.287 이상)${RESET}
5024
4852
  ${WHITE_BRIGHT}tfx doctor${RESET} ${GRAY}CLI 진단 + 이슈 확인${RESET}
5025
4853
  ${DIM} --fix${RESET} ${GRAY}진단 + 자동 수정${RESET}
5026
4854
  ${DIM} --reset${RESET} ${GRAY}캐시 전체 초기화${RESET}
5027
4855
  ${DIM} --json${RESET} ${GRAY}구조화된 진단 결과 JSON 출력${RESET}
5028
- ${WHITE_BRIGHT}tfx auto${RESET} ${GRAY}tfx-auto 라우팅 결정 미리보기 (--cli codex|antigravity|claude)${RESET}
5029
4856
  ${WHITE_BRIGHT}tfx stealth-fetch${RESET} ${GRAY}cloakbrowser 기반 URL fetch (JSON stdout)${RESET}
5030
4857
  ${WHITE_BRIGHT}tfx mcp${RESET} ${GRAY}MCP registry 관리 (list/sync/add/remove)${RESET}
5031
4858
  ${WHITE_BRIGHT}tfx update${RESET} ${GRAY}최신 안정 버전으로 업데이트${RESET}
@@ -5035,9 +4862,7 @@ ${updateNotice}
5035
4862
  ${WHITE_BRIGHT}tfx schema${RESET} ${GRAY}CLI/Hub schema JSON 출력${RESET}
5036
4863
  ${WHITE_BRIGHT}tfx hub${RESET} ${GRAY}MCP 메시지 버스 관리 (start/stop/status)${RESET}
5037
4864
  ${WHITE_BRIGHT}tfx multi${RESET} ${GRAY}멀티-CLI 팀 모드 (tmux + Hub)${RESET}
5038
- ${WHITE_BRIGHT}tfx swarm${RESET} ${GRAY}PRD 기반 worktree 격리 병렬 실행 (run/plan/list)${RESET}
5039
4865
  ${WHITE_BRIGHT}tfx synapse${RESET} ${GRAY}스웜 세션 registry 조회 / lease 관리${RESET}
5040
- ${WHITE_BRIGHT}tfx review${RESET} ${GRAY}Codex 기반 git diff review${RESET}
5041
4866
  ${WHITE_BRIGHT}tfx why${RESET} ${GRAY}경로의 마지막 커밋 X-Intent 트레일러 추출${RESET}
5042
4867
  ${WHITE_BRIGHT}tfx codex-team${RESET} ${GRAY}Codex 전용 팀 모드 (기본 lead/agents: codex)${RESET}
5043
4868
  ${WHITE_BRIGHT}tfx notion-read${RESET} ${GRAY}Notion 페이지 → 마크다운 (Codex/Gemini MCP)${RESET}
@@ -5045,7 +4870,7 @@ ${updateNotice}
5045
4870
 
5046
4871
  ${BOLD}Skills${RESET} ${GRAY}(Claude Code 슬래시 커맨드)${RESET}
5047
4872
 
5048
- ${AMBER}/tfx-auto${RESET} ${GRAY}자동 분류 + 병렬 실행 (--cli codex|antigravity|claude, --parallel N|swarm)${RESET}
4873
+ ${AMBER}/tfx-auto${RESET} ${GRAY}자동 분류 + 병렬 실행 (--cli codex|antigravity|claude, --parallel N)${RESET}
5049
4874
  ${AMBER}/tfx-setup${RESET} ${GRAY}HUD 설정 + 진단${RESET}
5050
4875
  ${YELLOW}/tfx-doctor${RESET} ${GRAY}진단 + 수리 + 캐시 초기화${RESET}
5051
4876
 
@@ -5920,31 +5745,6 @@ function parsePositiveIntegerOption(args, name, fallback) {
5920
5745
  return parsed;
5921
5746
  }
5922
5747
 
5923
- function applyAutoDispatchDecision(parsedArgs, decision = null) {
5924
- const resolved = decision || decideDispatchMode(parsedArgs);
5925
- if (resolved.warning) {
5926
- process.stderr.write(`${resolved.warning}\n`);
5927
- }
5928
- if (resolved.escalated) {
5929
- const logLine = `${JSON.stringify({
5930
- at: new Date().toISOString(),
5931
- issue: 281,
5932
- from: "multi",
5933
- to: "swarm",
5934
- tasksCount: Array.isArray(parsedArgs.tasks)
5935
- ? parsedArgs.tasks.length
5936
- : (parsedArgs.tasks ?? null),
5937
- reason: resolved.reason,
5938
- })}\n`;
5939
- try {
5940
- appendFileSync(".omc/state/auto-escalation.log", logLine, "utf8");
5941
- } catch {
5942
- // Fresh checkouts may not have .omc/state yet; dispatch should continue.
5943
- }
5944
- }
5945
- return resolved;
5946
- }
5947
-
5948
5748
  async function main() {
5949
5749
  const cmd = NORMALIZED_ARGS[0] || "help";
5950
5750
  const cmdArgs = NORMALIZED_ARGS.slice(1);
@@ -5954,20 +5754,6 @@ async function main() {
5954
5754
  }).catch(() => {});
5955
5755
 
5956
5756
  switch (cmd) {
5957
- case "auto": {
5958
- if (cmdArgs.some(isHelpArg)) {
5959
- printCommandHelp("auto");
5960
- return;
5961
- }
5962
- const parsedArgs = parseRouteArgs(cmdArgs);
5963
- const decision = applyAutoDispatchDecision(parsedArgs);
5964
- if (JSON_OUTPUT) {
5965
- printJson({ args: parsedArgs, dispatch: decision });
5966
- } else {
5967
- process.stdout.write(`${decision.mode}\n`);
5968
- }
5969
- return;
5970
- }
5971
5757
  case "setup":
5972
5758
  if (cmdArgs.some(isHelpArg)) {
5973
5759
  printCommandHelp("setup");
@@ -5977,6 +5763,7 @@ async function main() {
5977
5763
  dryRun: cmdArgs.includes("--dry-run"),
5978
5764
  fromUpdate: cmdArgs.includes("--from-update"),
5979
5765
  enableHubAutostart: cmdArgs.includes("--enable-hub-autostart"),
5766
+ mods: cmdArgs.includes("--mods"),
5980
5767
  });
5981
5768
  return;
5982
5769
  case "stealth-fetch":
@@ -6028,45 +5815,6 @@ async function main() {
6028
5815
  }
6029
5816
  return;
6030
5817
  }
6031
- if (cmdArgs.includes("--dynamic-routing")) {
6032
- const { diagnoseDynamicRouting } = await import(
6033
- "../scripts/doctor-dynamic-routing.mjs"
6034
- );
6035
- const report = await diagnoseDynamicRouting();
6036
- if (JSON_OUTPUT) {
6037
- console.log(JSON.stringify(report, null, 2));
6038
- } else {
6039
- const mark = (b) =>
6040
- b ? `${GREEN_BRIGHT}✓${RESET}` : `${RED}✗${RESET}`;
6041
- console.log(
6042
- `\n ${AMBER}${BOLD}⬡ triflux doctor — dynamic routing${RESET}\n`,
6043
- );
6044
- console.log(
6045
- ` ${mark(report.enabled)} enabled: ${report.enabled} (TRIFLUX_DYNAMIC_ROUTING=${report.envFlag ?? "미설정"})`,
6046
- );
6047
- console.log(
6048
- ` ${mark(report.policyLoaded)} policy loaded: ${report.policyLoaded} (scenarios=${report.policyScenarios.length})`,
6049
- );
6050
- console.log(
6051
- ` ${mark(report.snapshotCached)} snapshot cache: ${
6052
- report.snapshotCached
6053
- ? `hit (age=${report.snapshotAgeMs}ms)`
6054
- : "miss"
6055
- }`,
6056
- );
6057
- if (report.previewDecision) {
6058
- const d = report.previewDecision;
6059
- console.log(
6060
- ` ${GREEN_BRIGHT}→${RESET} preview decision: scenario=${d.scenario}, mode=${d.mode}, lane=${d.lane}, shards[0].cli=${d.shards?.[0]?.cli ?? "?"}`,
6061
- );
6062
- }
6063
- if (report.error) {
6064
- console.log(` ${RED}✗${RESET} error: ${report.error}`);
6065
- }
6066
- console.log("");
6067
- }
6068
- return;
6069
- }
6070
5818
  const fix = cmdArgs.includes("--fix");
6071
5819
  const reset = cmdArgs.includes("--reset");
6072
5820
  const purgeLogs = cmdArgs.includes("--purge-logs");
@@ -6166,7 +5914,11 @@ async function main() {
6166
5914
  case "multi": {
6167
5915
  const subcommand = cmdArgs[0] || "";
6168
5916
  if (cmdArgs.some(isHelpArg)) {
6169
- printCommandHelp("multi");
5917
+ const { pathToFileURL } = await import("node:url");
5918
+ const { renderTeamHelp } = await import(
5919
+ pathToFileURL(join(PKG_ROOT, "hub", "team", "cli", "help.mjs")).href
5920
+ );
5921
+ renderTeamHelp();
6170
5922
  return;
6171
5923
  }
6172
5924
  if (JSON_OUTPUT) process.env.TFX_OUTPUT_JSON = "1";
@@ -6240,129 +5992,6 @@ async function main() {
6240
5992
  await cmdSynapseStatus(cmdArgs.slice(1), { json: JSON_OUTPUT });
6241
5993
  return;
6242
5994
  }
6243
- case "review": {
6244
- if (cmdArgs.some(isHelpArg)) {
6245
- printCommandHelp("review");
6246
- return;
6247
- }
6248
- const ref =
6249
- cmdArgs[0] && !cmdArgs[0].startsWith("--") ? cmdArgs[0] : "HEAD";
6250
- const baseIdx = cmdArgs.indexOf("--base");
6251
- const base = baseIdx >= 0 ? cmdArgs[baseIdx + 1] : undefined;
6252
- const timeoutIdx = cmdArgs.indexOf("--timeout");
6253
- const timeoutMs =
6254
- timeoutIdx >= 0 ? Number(cmdArgs[timeoutIdx + 1]) * 1000 : 180_000;
6255
- const shardIdx = cmdArgs.indexOf("--shard");
6256
- const shard = shardIdx >= 0 ? cmdArgs[shardIdx + 1] : "off";
6257
-
6258
- if (shard === "per-file") {
6259
- const { runCodexReviewSharded } = await import(
6260
- "../hub/team/codex-review.mjs"
6261
- );
6262
- const result = await runCodexReviewSharded({
6263
- ref,
6264
- base,
6265
- timeoutMs,
6266
- onFileStart: ({ file, index, total }) => {
6267
- if (!JSON_OUTPUT) {
6268
- process.stderr.write(
6269
- `[${index + 1}/${total}] reviewing ${file}\n`,
6270
- );
6271
- }
6272
- },
6273
- });
6274
- if (JSON_OUTPUT) {
6275
- console.log(JSON.stringify(result, null, 2));
6276
- } else {
6277
- console.log(
6278
- `=== per-file review (${result.files.length} files, range=${result.range}) ===`,
6279
- );
6280
- for (const r of result.perFile) {
6281
- console.log("");
6282
- console.log(
6283
- `--- ${r.file} (${r.diffBytes}b, verdict=${r.verdict || "n/a"}${r.skipped ? ", skipped" : ""}) ---`,
6284
- );
6285
- if (r.error) console.log(` error: ${r.error}`);
6286
- if (r.stdout) process.stdout.write(r.stdout);
6287
- }
6288
- console.log("");
6289
- console.log(
6290
- `Aggregate: files=${result.files.length} verdict=${result.verdict}`,
6291
- );
6292
- if (result.error) console.log(`error: ${result.error}`);
6293
- }
6294
- process.exit(result.ok ? 0 : 1);
6295
- }
6296
-
6297
- const { runCodexReview } = await import("../hub/team/codex-review.mjs");
6298
- const result = await runCodexReview({ ref, base, timeoutMs });
6299
- if (JSON_OUTPUT) {
6300
- console.log(JSON.stringify(result, null, 2));
6301
- } else {
6302
- if (result.stdout) process.stdout.write(result.stdout);
6303
- if (result.stderr) process.stderr.write(result.stderr);
6304
- console.log("");
6305
- console.log(
6306
- `range=${result.range || ref} diffBytes=${result.diffBytes} verdict=${result.verdict || "n/a"}`,
6307
- );
6308
- if (result.error) console.log(`error: ${result.error}`);
6309
- }
6310
- process.exit(result.ok ? 0 : 1);
6311
- return;
6312
- }
6313
- case "swarm": {
6314
- const sub = cmdArgs[0] || "";
6315
- if (sub === "help" || sub === "--help" || sub === "-h") {
6316
- const s = CLI_COMMAND_SCHEMAS.swarm;
6317
- console.log(`
6318
- ${AMBER}${BOLD}⬡ tfx swarm${RESET}
6319
-
6320
- ${GRAY}${s.description}${RESET}
6321
-
6322
- ${BOLD}Usage${RESET}
6323
- ${WHITE_BRIGHT}${s.usage}${RESET}
6324
-
6325
- ${BOLD}Subcommands${RESET}
6326
- ${WHITE_BRIGHT}tfx swarm run <prd>${RESET} ${GRAY}${s.subcommands.run}${RESET}
6327
- ${WHITE_BRIGHT}tfx swarm preflight <prd>${RESET} ${GRAY}${s.subcommands.preflight}${RESET}
6328
- ${WHITE_BRIGHT}tfx swarm plan <prd>${RESET} ${GRAY}${s.subcommands.plan}${RESET}
6329
- ${WHITE_BRIGHT}tfx swarm list${RESET} ${GRAY}${s.subcommands.list}${RESET}
6330
- ${WHITE_BRIGHT}tfx swarm status${RESET} ${GRAY}${s.subcommands.status}${RESET}
6331
-
6332
- ${BOLD}Options${RESET}
6333
- ${s.options.map((o) => ` ${DIM}${o.name.padEnd(16)}${RESET} ${GRAY}${o.description}${RESET}`).join("\n")}
6334
- `);
6335
- return;
6336
- }
6337
- await checkHubRunning();
6338
- const { cmdSwarmRun, cmdSwarmPlan, cmdSwarmList, cmdSwarmPreflight } =
6339
- await import("../hub/team/swarm-cli.mjs");
6340
- if (sub === "list" || sub === "status") {
6341
- await cmdSwarmList(cmdArgs.slice(1), { json: JSON_OUTPUT });
6342
- return;
6343
- }
6344
- if (sub === "plan") {
6345
- await cmdSwarmPlan(cmdArgs.slice(1), { json: JSON_OUTPUT });
6346
- return;
6347
- }
6348
- if (sub === "preflight") {
6349
- await cmdSwarmPreflight(cmdArgs.slice(1), { json: JSON_OUTPUT });
6350
- return;
6351
- }
6352
- if (sub === "run") {
6353
- await cmdSwarmRun(cmdArgs.slice(1), { json: JSON_OUTPUT });
6354
- return;
6355
- }
6356
- if (!sub || sub.startsWith("--")) {
6357
- throw createCliError("PRD 경로가 필요합니다", {
6358
- exitCode: EXIT_ARG_ERROR,
6359
- reason: "argError",
6360
- fix: "tfx swarm [run] <prd-path> [--dry-run|--json|--filter <shard>]",
6361
- });
6362
- }
6363
- await cmdSwarmRun(cmdArgs, { json: JSON_OUTPUT });
6364
- return;
6365
- }
6366
5995
  case "why": {
6367
5996
  if (cmdArgs.some(isHelpArg)) {
6368
5997
  printCommandHelp("why");
package/cto/brief.mjs CHANGED
@@ -27,13 +27,6 @@ function formatGoal(goal) {
27
27
  return `- ${id} ${status}: ${title}`;
28
28
  }
29
29
 
30
- function formatShard(shard) {
31
- const id = oneLine(shard?.id || shard?.name || shard?.sessionId, "shard");
32
- const status = oneLine(shard?.status || shard?.state, "unknown");
33
- const detail = oneLine(shard?.summary || shard?.objective || shard?.task, "");
34
- return detail ? `- ${id} ${status}: ${detail}` : `- ${id} ${status}`;
35
- }
36
-
37
30
  function formatEvent(event) {
38
31
  const ts = oneLine(event?.ts, "unknown_ts");
39
32
  const name = oneLine(event?.event, "event");
@@ -61,9 +54,6 @@ export function renderBrief(current) {
61
54
  const activeGoals = Array.isArray(summary.active_goals)
62
55
  ? summary.active_goals.slice(0, 3)
63
56
  : [];
64
- const swarmShards = Array.isArray(summary.swarm_shards)
65
- ? summary.swarm_shards.slice(0, 2)
66
- : [];
67
57
  const recentEvents = Array.isArray(current?.ledger_tail)
68
58
  ? current.ledger_tail.slice(-2)
69
59
  : [];
@@ -75,8 +65,6 @@ export function renderBrief(current) {
75
65
  `summary: ${oneLine(summary.repo_state, "no repo summary")}`,
76
66
  "active_goals",
77
67
  ...(activeGoals.length > 0 ? activeGoals.map(formatGoal) : ["- none"]),
78
- "swarm_shards",
79
- ...(swarmShards.length > 0 ? swarmShards.map(formatShard) : ["- none"]),
80
68
  "hub_status",
81
69
  `status: ${oneLine(hub.status, "unknown")} available: ${hub.available === true} detail: ${compactDetail(hub.detail)}`,
82
70
  "recent_events",