triflux 10.26.0 → 10.28.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/README.ko.md +30 -25
- package/README.md +23 -19
- package/bin/triflux.mjs +327 -27
- package/config/mcp-registry.json +10 -6
- package/docs/assets/architecture.svg +211 -0
- package/docs/assets/consensus-flow.svg +125 -0
- package/docs/assets/deep-vs-light.svg +193 -0
- package/docs/assets/demo-dark.gif +0 -0
- package/docs/assets/demo-light.gif +0 -0
- package/docs/assets/demo-multi.gif +0 -0
- package/docs/assets/demo-psmux.gif +0 -0
- package/docs/assets/logo-dark.svg +29 -0
- package/docs/assets/logo-light.svg +29 -0
- package/docs/assets/social-preview.png +0 -0
- package/docs/assets/social-preview.svg +80 -0
- package/hub/lib/tfx-route-args.mjs +10 -3
- package/hub/team/claude-daemon-control.mjs +214 -0
- package/hub/team/claude-native-bridge.mjs +51 -73
- package/hub/team/daemon-pty-tmux-bridge.mjs +146 -0
- package/hub/team/headless.mjs +23 -42
- package/hub/team/interactive-native-launcher.mjs +88 -75
- package/hub/team/retry-state-machine.mjs +2 -2
- package/hub/team/swarm-hypervisor.mjs +35 -8
- package/hub/team/uds-orchestrator.mjs +348 -0
- package/hud/context-monitor.mjs +7 -2
- package/package.json +6 -3
- package/scripts/__tests__/mcp-gateway-health-check.test.mjs +53 -0
- package/scripts/__tests__/mcp-guard-engine-policy-sync.test.mjs +8 -8
- package/scripts/codex-gateway-preflight.mjs +82 -22
- package/scripts/codex-mcp-gateway-sync.mjs +65 -31
- package/scripts/completions/tfx.bash +47 -14
- package/scripts/completions/tfx.fish +50 -33
- package/scripts/completions/tfx.zsh +68 -43
- package/scripts/demo.mjs +15 -5
- package/scripts/lib/mcp-gateway-health-check.mjs +65 -0
- package/scripts/lib/mcp-guard-engine.mjs +52 -8
- package/scripts/mcp-gateway-config.mjs +13 -13
- package/scripts/mcp-gateway-ensure.mjs +27 -12
- package/scripts/mcp-gateway-integration-test.mjs +21 -15
- package/scripts/mcp-gateway-start.mjs +6 -3
- package/scripts/mcp-gateway-start.ps1 +3 -3
- package/scripts/mcp-gateway-verify.mjs +1 -1
- package/scripts/release/check-packages-mirror.mjs +5 -0
- package/scripts/session-stale-cleanup.mjs +31 -1
- package/scripts/sync-hub-mcp-settings.mjs +30 -14
- package/skills/tfx-setup/SKILL.md +4 -4
- package/tui/codex-profile.mjs +409 -0
- package/tui/core.mjs +266 -0
- package/tui/doctor.mjs +375 -0
- package/tui/gemini-profile.mjs +299 -0
- package/tui/monitor-data.mjs +152 -0
- package/tui/monitor.mjs +317 -0
- package/tui/setup.mjs +633 -0
package/bin/triflux.mjs
CHANGED
|
@@ -143,6 +143,34 @@ const JSON_OUTPUT = RAW_ARGS.includes("--json");
|
|
|
143
143
|
const NORMALIZED_ARGS = RAW_ARGS.filter((arg) => arg !== "--json");
|
|
144
144
|
|
|
145
145
|
const CLI_COMMAND_SCHEMAS = Object.freeze({
|
|
146
|
+
auto: {
|
|
147
|
+
usage:
|
|
148
|
+
"tfx auto [--cli auto|codex|antigravity|claude] [--mode quick|deep|consensus] [--parallel 1|N|swarm] [--json]",
|
|
149
|
+
description:
|
|
150
|
+
"tfx-auto 라우팅 결정을 CLI에서 미리보기/직렬화 (실행 skill front door와 같은 flag surface)",
|
|
151
|
+
options: [
|
|
152
|
+
{
|
|
153
|
+
name: "--cli <name>",
|
|
154
|
+
type: "string",
|
|
155
|
+
description: "실행 lane 강제: auto|codex|antigravity|claude",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "--mode <name>",
|
|
159
|
+
type: "string",
|
|
160
|
+
description: "라우팅 모드: quick|deep|consensus",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "--parallel <1|N|swarm>",
|
|
164
|
+
type: "string",
|
|
165
|
+
description: "단일/로컬 병렬/PRD swarm 라우팅 힌트",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "--json",
|
|
169
|
+
type: "boolean",
|
|
170
|
+
description: "parse 결과와 dispatch 결정을 JSON으로 출력",
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
},
|
|
146
174
|
setup: {
|
|
147
175
|
usage: "tfx setup [--dry-run] [--enable-hub-autostart]",
|
|
148
176
|
description: "파일 동기화 + HUD/MCP 설정",
|
|
@@ -498,6 +526,102 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
|
|
|
498
526
|
},
|
|
499
527
|
},
|
|
500
528
|
},
|
|
529
|
+
update: {
|
|
530
|
+
usage: "tfx update [--dev]",
|
|
531
|
+
description:
|
|
532
|
+
"설치 방식(plugin/npm/git)을 감지해 triflux를 업데이트하고 setup/cache를 재동기화",
|
|
533
|
+
options: [
|
|
534
|
+
{
|
|
535
|
+
name: "--dev / dev",
|
|
536
|
+
type: "boolean",
|
|
537
|
+
description: "npm 설치 모드에서 dev tag로 업데이트",
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
name: "--help",
|
|
541
|
+
type: "boolean",
|
|
542
|
+
description: "업데이트를 실행하지 않고 도움말만 출력",
|
|
543
|
+
},
|
|
544
|
+
],
|
|
545
|
+
},
|
|
546
|
+
tray: {
|
|
547
|
+
usage: "tfx tray [--attach]",
|
|
548
|
+
description: "트레이/HUD 상태 표시 프로세스 실행",
|
|
549
|
+
options: [
|
|
550
|
+
{
|
|
551
|
+
name: "--attach",
|
|
552
|
+
type: "boolean",
|
|
553
|
+
description: "디버깅용 foreground 실행 (기본은 detach)",
|
|
554
|
+
},
|
|
555
|
+
],
|
|
556
|
+
},
|
|
557
|
+
"codex-team": {
|
|
558
|
+
usage:
|
|
559
|
+
"tfx codex-team [status|debug|send|attach|stop|<task>] [--layout 1xN|Nx1] [--json]",
|
|
560
|
+
description:
|
|
561
|
+
"Codex lead + Codex workers 기본값으로 tfx multi 팀 모드를 시작/제어",
|
|
562
|
+
subcommands: {
|
|
563
|
+
status: "현재 Codex team 상태 확인",
|
|
564
|
+
debug: "최근 로그/상태 진단 출력",
|
|
565
|
+
send: "워커에게 메시지 전송: tfx codex-team send <N> <msg>",
|
|
566
|
+
attach: "팀 pane/session attach",
|
|
567
|
+
stop: "팀 세션 정리",
|
|
568
|
+
},
|
|
569
|
+
options: [
|
|
570
|
+
{
|
|
571
|
+
name: "--layout <shape>",
|
|
572
|
+
type: "string",
|
|
573
|
+
description: "기본 1xN. Nx1 등 team layout 전달",
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
name: "--json",
|
|
577
|
+
type: "boolean",
|
|
578
|
+
description: "지원 subcommand의 출력을 JSON으로 전환",
|
|
579
|
+
},
|
|
580
|
+
],
|
|
581
|
+
},
|
|
582
|
+
"notion-read": {
|
|
583
|
+
usage: "tfx notion-read <notion-url-or-page-id> [options]",
|
|
584
|
+
description: "Notion page/database를 markdown/JSON으로 읽기 (nr alias)",
|
|
585
|
+
aliases: ["nr"],
|
|
586
|
+
options: [
|
|
587
|
+
{
|
|
588
|
+
name: "--json",
|
|
589
|
+
type: "boolean",
|
|
590
|
+
description: "가능한 경우 구조화된 JSON 출력",
|
|
591
|
+
},
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
review: {
|
|
595
|
+
usage:
|
|
596
|
+
"tfx review [ref] [--base <ref>] [--timeout <seconds>] [--shard off|per-file] [--json]",
|
|
597
|
+
description: "Codex 기반 git diff review 실행",
|
|
598
|
+
options: [
|
|
599
|
+
{
|
|
600
|
+
name: "--base <ref>",
|
|
601
|
+
type: "string",
|
|
602
|
+
description: "비교 기준 ref",
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
name: "--timeout <seconds>",
|
|
606
|
+
type: "number",
|
|
607
|
+
description: "review 실행 timeout (기본 180)",
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
name: "--shard <mode>",
|
|
611
|
+
type: "string",
|
|
612
|
+
description: "off 또는 per-file",
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: "--json",
|
|
616
|
+
type: "boolean",
|
|
617
|
+
description: "review 결과 JSON 출력",
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
},
|
|
621
|
+
monitor: {
|
|
622
|
+
usage: "tfx monitor",
|
|
623
|
+
description: "터미널 TUI 모니터 실행",
|
|
624
|
+
},
|
|
501
625
|
});
|
|
502
626
|
|
|
503
627
|
// ── 유틸리티 ──
|
|
@@ -525,6 +649,53 @@ function printJson(payload) {
|
|
|
525
649
|
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
526
650
|
}
|
|
527
651
|
|
|
652
|
+
function isHelpArg(arg) {
|
|
653
|
+
return ["help", "--help", "-h"].includes(String(arg || "").toLowerCase());
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function formatSubcommandHelp(name, entry) {
|
|
657
|
+
if (typeof entry === "string") return `${name} — ${entry}`;
|
|
658
|
+
if (entry?.usage && entry?.description) {
|
|
659
|
+
return `${entry.usage} — ${entry.description}`;
|
|
660
|
+
}
|
|
661
|
+
if (entry?.usage) return entry.usage;
|
|
662
|
+
if (entry?.description) return `${name} — ${entry.description}`;
|
|
663
|
+
return String(name);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function printCommandHelp(command) {
|
|
667
|
+
const schema = CLI_COMMAND_SCHEMAS[command];
|
|
668
|
+
if (!schema) return false;
|
|
669
|
+
const subcommands = schema.subcommands
|
|
670
|
+
? Object.entries(schema.subcommands)
|
|
671
|
+
.map(
|
|
672
|
+
([name, entry]) =>
|
|
673
|
+
` ${WHITE_BRIGHT}${formatSubcommandHelp(name, entry)}${RESET}`,
|
|
674
|
+
)
|
|
675
|
+
.join("\n")
|
|
676
|
+
: "";
|
|
677
|
+
const options = schema.options
|
|
678
|
+
? schema.options
|
|
679
|
+
.map(
|
|
680
|
+
(option) =>
|
|
681
|
+
` ${DIM}${String(option.name).padEnd(22)}${RESET} ${GRAY}${option.description || ""}${RESET}`,
|
|
682
|
+
)
|
|
683
|
+
.join("\n")
|
|
684
|
+
: "";
|
|
685
|
+
const aliases = schema.aliases?.length
|
|
686
|
+
? `\n ${BOLD}Aliases${RESET}\n ${schema.aliases.join(", ")}\n`
|
|
687
|
+
: "";
|
|
688
|
+
console.log(`
|
|
689
|
+
${AMBER}${BOLD}⬡ tfx ${command}${RESET}
|
|
690
|
+
|
|
691
|
+
${GRAY}${schema.description || ""}${RESET}
|
|
692
|
+
|
|
693
|
+
${BOLD}Usage${RESET}
|
|
694
|
+
${WHITE_BRIGHT}${schema.usage}${RESET}
|
|
695
|
+
${aliases}${subcommands ? `\n ${BOLD}Subcommands${RESET}\n${subcommands}\n` : ""}${options ? `\n ${BOLD}Options${RESET}\n${options}\n` : ""}`);
|
|
696
|
+
return true;
|
|
697
|
+
}
|
|
698
|
+
|
|
528
699
|
async function withConsoleSilenced(enabled, fn) {
|
|
529
700
|
if (!enabled) return fn();
|
|
530
701
|
const originalLog = console.log;
|
|
@@ -2064,32 +2235,36 @@ function cmdSetup(options = {}) {
|
|
|
2064
2235
|
});
|
|
2065
2236
|
}
|
|
2066
2237
|
|
|
2067
|
-
// Gemini 프로필
|
|
2238
|
+
// Antigravity/Gemini 호환 프로필
|
|
2068
2239
|
const geminiResult = ensureGeminiProfiles();
|
|
2069
2240
|
if (!geminiResult.ok) {
|
|
2070
2241
|
const reason = renderErrorMessage(geminiResult.message);
|
|
2071
|
-
warn(`Gemini profiles 설정 실패: ${reason}`);
|
|
2072
|
-
summary.push({
|
|
2242
|
+
warn(`Antigravity/Gemini profiles 설정 실패: ${reason}`);
|
|
2243
|
+
summary.push({
|
|
2244
|
+
item: "Antigravity/Gemini profiles",
|
|
2245
|
+
status: "⚠️",
|
|
2246
|
+
detail: reason,
|
|
2247
|
+
});
|
|
2073
2248
|
} else if (geminiResult.created) {
|
|
2074
2249
|
ok(
|
|
2075
|
-
`Gemini profiles: ${geminiResult.count}개 생성됨 (~/.gemini/triflux-profiles.json)`,
|
|
2250
|
+
`Antigravity/Gemini profiles: ${geminiResult.count}개 생성됨 (~/.gemini/triflux-profiles.json)`,
|
|
2076
2251
|
);
|
|
2077
2252
|
summary.push({
|
|
2078
|
-
item: "Gemini profiles",
|
|
2253
|
+
item: "Antigravity/Gemini profiles",
|
|
2079
2254
|
status: "✅",
|
|
2080
2255
|
detail: `${geminiResult.count}개 생성됨`,
|
|
2081
2256
|
});
|
|
2082
2257
|
} else if (geminiResult.added > 0) {
|
|
2083
|
-
ok(`Gemini profiles: ${geminiResult.added}개 추가됨`);
|
|
2258
|
+
ok(`Antigravity/Gemini profiles: ${geminiResult.added}개 추가됨`);
|
|
2084
2259
|
summary.push({
|
|
2085
|
-
item: "Gemini profiles",
|
|
2260
|
+
item: "Antigravity/Gemini profiles",
|
|
2086
2261
|
status: "✅",
|
|
2087
2262
|
detail: `${geminiResult.added}개 추가됨 (총 ${geminiResult.count}개)`,
|
|
2088
2263
|
});
|
|
2089
2264
|
} else {
|
|
2090
|
-
ok(`Gemini profiles: ${geminiResult.count}개 준비됨`);
|
|
2265
|
+
ok(`Antigravity/Gemini profiles: ${geminiResult.count}개 준비됨`);
|
|
2091
2266
|
summary.push({
|
|
2092
|
-
item: "Gemini profiles",
|
|
2267
|
+
item: "Antigravity/Gemini profiles",
|
|
2093
2268
|
status: "✅",
|
|
2094
2269
|
detail: `${geminiResult.count}개 준비됨`,
|
|
2095
2270
|
});
|
|
@@ -4689,10 +4864,9 @@ async function cmdDoctor(options = {}) {
|
|
|
4689
4864
|
// skip 된 server 를 잡는다. 로그가 없으면 gateway 미설치/미실행으로 침묵.
|
|
4690
4865
|
section("MCP Gateway Health");
|
|
4691
4866
|
{
|
|
4692
|
-
const {
|
|
4693
|
-
"../scripts/lib/mcp-gateway-health-check.mjs"
|
|
4694
|
-
);
|
|
4695
|
-
const gatewayHealth = checkMcpGatewayHealth();
|
|
4867
|
+
const { checkMcpGatewayHealthLive, summarizeMcpGatewayHealth } =
|
|
4868
|
+
await import("../scripts/lib/mcp-gateway-health-check.mjs");
|
|
4869
|
+
const gatewayHealth = await checkMcpGatewayHealthLive();
|
|
4696
4870
|
const summary = summarizeMcpGatewayHealth(gatewayHealth);
|
|
4697
4871
|
addDoctorCheck(report, {
|
|
4698
4872
|
name: "mcp-gateway-health",
|
|
@@ -4700,6 +4874,7 @@ async function cmdDoctor(options = {}) {
|
|
|
4700
4874
|
log_path: gatewayHealth.logPath,
|
|
4701
4875
|
findings: gatewayHealth.findings,
|
|
4702
4876
|
started: gatewayHealth.started,
|
|
4877
|
+
live: gatewayHealth.live,
|
|
4703
4878
|
skipped: gatewayHealth.skipped,
|
|
4704
4879
|
...(summary.fix ? { fix: summary.fix } : {}),
|
|
4705
4880
|
});
|
|
@@ -5163,8 +5338,13 @@ function resolveUpdateTargets({ installMode, pluginPath }) {
|
|
|
5163
5338
|
return [];
|
|
5164
5339
|
}
|
|
5165
5340
|
|
|
5166
|
-
async function cmdUpdate() {
|
|
5167
|
-
|
|
5341
|
+
async function cmdUpdate(args = []) {
|
|
5342
|
+
if (args.some(isHelpArg)) {
|
|
5343
|
+
printCommandHelp("update");
|
|
5344
|
+
return;
|
|
5345
|
+
}
|
|
5346
|
+
|
|
5347
|
+
const isDev = isDevUpdateRequested(args);
|
|
5168
5348
|
const tagLabel = isDev ? ` ${YELLOW}--dev${RESET}` : "";
|
|
5169
5349
|
console.log(`\n${BOLD}triflux update${RESET}${tagLabel}\n`);
|
|
5170
5350
|
|
|
@@ -5520,29 +5700,76 @@ async function cmdUpdate() {
|
|
|
5520
5700
|
console.log(`${GREEN}${BOLD}✓ 업데이트 완료${RESET}\n`);
|
|
5521
5701
|
}
|
|
5522
5702
|
|
|
5703
|
+
function readPackagedSkillMetadata(skillName) {
|
|
5704
|
+
const skillPath = join(PKG_ROOT, "skills", skillName, "SKILL.md");
|
|
5705
|
+
if (!existsSync(skillPath)) return null;
|
|
5706
|
+
const metadata = { name: skillName, deprecated: false, supersededBy: null };
|
|
5707
|
+
let inFrontmatter = false;
|
|
5708
|
+
for (const line of readFileSync(skillPath, "utf8").split(/\r?\n/)) {
|
|
5709
|
+
if (line.trim() === "---") {
|
|
5710
|
+
if (!inFrontmatter) {
|
|
5711
|
+
inFrontmatter = true;
|
|
5712
|
+
continue;
|
|
5713
|
+
}
|
|
5714
|
+
break;
|
|
5715
|
+
}
|
|
5716
|
+
if (!inFrontmatter) continue;
|
|
5717
|
+
const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
5718
|
+
if (!match) continue;
|
|
5719
|
+
const [, key, rawValue] = match;
|
|
5720
|
+
const value = rawValue.trim().replace(/^["']|["']$/g, "");
|
|
5721
|
+
if (key === "deprecated") metadata.deprecated = value === "true";
|
|
5722
|
+
if (key === "superseded-by") metadata.supersededBy = value || null;
|
|
5723
|
+
}
|
|
5724
|
+
return metadata;
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5727
|
+
function listDeprecatedPackagedSkillAliases(pluginSkills, installedSkills) {
|
|
5728
|
+
if (!existsSync(pluginSkills)) return [];
|
|
5729
|
+
return readdirSync(pluginSkills)
|
|
5730
|
+
.sort()
|
|
5731
|
+
.map((name) => readPackagedSkillMetadata(name))
|
|
5732
|
+
.filter((metadata) => metadata?.deprecated)
|
|
5733
|
+
.map((metadata) => ({
|
|
5734
|
+
alias: metadata.name,
|
|
5735
|
+
source: metadata.supersededBy || "deprecated",
|
|
5736
|
+
installed: existsSync(join(installedSkills, metadata.name, "SKILL.md")),
|
|
5737
|
+
deprecated: true,
|
|
5738
|
+
}));
|
|
5739
|
+
}
|
|
5740
|
+
|
|
5523
5741
|
function cmdList(options = {}) {
|
|
5524
5742
|
const { json = false } = options;
|
|
5525
5743
|
const pluginSkills = join(PKG_ROOT, "skills");
|
|
5526
5744
|
const installedSkills = join(CLAUDE_DIR, "skills");
|
|
5527
5745
|
const packageSkills = [];
|
|
5528
5746
|
const userSkills = [];
|
|
5529
|
-
const
|
|
5530
|
-
|
|
5747
|
+
const skillAliases = listDeprecatedPackagedSkillAliases(
|
|
5748
|
+
pluginSkills,
|
|
5749
|
+
installedSkills,
|
|
5750
|
+
);
|
|
5751
|
+
const aliasNames = new Set([
|
|
5752
|
+
...SKILL_ALIASES.map(({ alias }) => alias),
|
|
5753
|
+
...skillAliases.map(({ alias }) => alias),
|
|
5754
|
+
]);
|
|
5531
5755
|
|
|
5532
5756
|
if (existsSync(pluginSkills)) {
|
|
5533
5757
|
for (const name of readdirSync(pluginSkills).sort()) {
|
|
5534
5758
|
const src = join(pluginSkills, name, "SKILL.md");
|
|
5535
5759
|
if (!existsSync(src)) continue;
|
|
5760
|
+
const metadata = readPackagedSkillMetadata(name);
|
|
5536
5761
|
const dst = join(installedSkills, name, "SKILL.md");
|
|
5537
|
-
packageSkills.push({
|
|
5762
|
+
packageSkills.push({
|
|
5763
|
+
name,
|
|
5764
|
+
installed: existsSync(dst),
|
|
5765
|
+
...(metadata?.deprecated ? { deprecated: true } : {}),
|
|
5766
|
+
...(metadata?.supersededBy
|
|
5767
|
+
? { superseded_by: metadata.supersededBy }
|
|
5768
|
+
: {}),
|
|
5769
|
+
});
|
|
5538
5770
|
}
|
|
5539
5771
|
}
|
|
5540
5772
|
|
|
5541
|
-
for (const { alias, source } of SKILL_ALIASES) {
|
|
5542
|
-
const dst = join(installedSkills, alias, "SKILL.md");
|
|
5543
|
-
skillAliases.push({ alias, source, installed: existsSync(dst) });
|
|
5544
|
-
}
|
|
5545
|
-
|
|
5546
5773
|
const pkgNames = new Set(
|
|
5547
5774
|
existsSync(pluginSkills) ? readdirSync(pluginSkills) : [],
|
|
5548
5775
|
);
|
|
@@ -5593,7 +5820,7 @@ function cmdList(options = {}) {
|
|
|
5593
5820
|
: `${RED_BRIGHT}↳${RESET}`;
|
|
5594
5821
|
const status = entry.installed ? "" : ` ${GRAY}(미설치)${RESET}`;
|
|
5595
5822
|
console.log(
|
|
5596
|
-
` ${icon} ${BOLD}${entry.alias}${RESET} ${GRAY}→ ${entry.source}${RESET}${status}`,
|
|
5823
|
+
` ${icon} ${BOLD}${entry.alias}${RESET} ${GRAY}→ ${entry.source}${RESET}${entry.deprecated ? ` ${YELLOW}(deprecated)${RESET}` : ""}${status}`,
|
|
5597
5824
|
);
|
|
5598
5825
|
}
|
|
5599
5826
|
}
|
|
@@ -5624,6 +5851,11 @@ function cmdVersion(options = {}) {
|
|
|
5624
5851
|
}
|
|
5625
5852
|
|
|
5626
5853
|
function cmdHandoff(args = [], options = {}) {
|
|
5854
|
+
if (args.some(isHelpArg)) {
|
|
5855
|
+
printCommandHelp("handoff");
|
|
5856
|
+
return;
|
|
5857
|
+
}
|
|
5858
|
+
|
|
5627
5859
|
const { json = false } = options;
|
|
5628
5860
|
const parsed = {
|
|
5629
5861
|
target: "remote",
|
|
@@ -5752,6 +5984,11 @@ function cmdSchema(args = []) {
|
|
|
5752
5984
|
? bundle["x-triflux-mcp-tools"].find((tool) => tool.name === selector)
|
|
5753
5985
|
: null;
|
|
5754
5986
|
|
|
5987
|
+
if (isHelpArg(selector)) {
|
|
5988
|
+
printCommandHelp("schema");
|
|
5989
|
+
return;
|
|
5990
|
+
}
|
|
5991
|
+
|
|
5755
5992
|
if (!selector) {
|
|
5756
5993
|
printJson({
|
|
5757
5994
|
$schema: bundle.$schema,
|
|
@@ -6084,18 +6321,21 @@ ${updateNotice}
|
|
|
6084
6321
|
${DIM} --fix${RESET} ${GRAY}진단 + 자동 수정${RESET}
|
|
6085
6322
|
${DIM} --reset${RESET} ${GRAY}캐시 전체 초기화${RESET}
|
|
6086
6323
|
${DIM} --json${RESET} ${GRAY}구조화된 진단 결과 JSON 출력${RESET}
|
|
6324
|
+
${WHITE_BRIGHT}tfx auto${RESET} ${GRAY}tfx-auto 라우팅 결정 미리보기 (--cli codex|antigravity|claude)${RESET}
|
|
6087
6325
|
${WHITE_BRIGHT}tfx mcp${RESET} ${GRAY}MCP registry 관리 (list/sync/add/remove)${RESET}
|
|
6088
6326
|
${WHITE_BRIGHT}tfx update${RESET} ${GRAY}최신 안정 버전으로 업데이트${RESET}
|
|
6089
6327
|
${DIM} --dev / dev${RESET} ${GRAY}dev 태그로 업데이트${RESET}
|
|
6090
6328
|
${WHITE_BRIGHT}tfx list${RESET} ${GRAY}설치된 스킬 목록${RESET}
|
|
6091
6329
|
${WHITE_BRIGHT}tfx handoff${RESET} ${GRAY}현재 컨텍스트를 원격/로컬 핸드오프 프롬프트로 생성${RESET}
|
|
6092
6330
|
${WHITE_BRIGHT}tfx schema${RESET} ${GRAY}CLI/Hub schema JSON 출력${RESET}
|
|
6331
|
+
${WHITE_BRIGHT}tfx hooks${RESET} ${GRAY}훅 오케스트레이터 scan/diff/apply/status${RESET}
|
|
6093
6332
|
${WHITE_BRIGHT}tfx hub${RESET} ${GRAY}MCP 메시지 버스 관리 (start/stop/status)${RESET}
|
|
6094
6333
|
${WHITE_BRIGHT}tfx tray${RESET} ${GRAY}Windows 시스템 트레이 실행${RESET}
|
|
6095
|
-
${DIM} --
|
|
6334
|
+
${DIM} --attach${RESET} ${GRAY}foreground 트레이 프로세스로 실행${RESET}
|
|
6096
6335
|
${WHITE_BRIGHT}tfx multi${RESET} ${GRAY}멀티-CLI 팀 모드 (tmux + Hub)${RESET}
|
|
6097
6336
|
${WHITE_BRIGHT}tfx swarm${RESET} ${GRAY}PRD 기반 worktree 격리 병렬 실행 (run/plan/list)${RESET}
|
|
6098
6337
|
${WHITE_BRIGHT}tfx synapse${RESET} ${GRAY}스웜 세션 registry 조회 / lease 관리${RESET}
|
|
6338
|
+
${WHITE_BRIGHT}tfx review${RESET} ${GRAY}Codex 기반 git diff review${RESET}
|
|
6099
6339
|
${WHITE_BRIGHT}tfx why${RESET} ${GRAY}경로의 마지막 커밋 X-Intent 트레일러 추출${RESET}
|
|
6100
6340
|
${WHITE_BRIGHT}tfx codex-team${RESET} ${GRAY}Codex 전용 팀 모드 (기본 lead/agents: codex)${RESET}
|
|
6101
6341
|
${WHITE_BRIGHT}tfx notion-read${RESET} ${GRAY}Notion 페이지 → 마크다운 (Codex/Gemini MCP)${RESET}
|
|
@@ -6103,7 +6343,7 @@ ${updateNotice}
|
|
|
6103
6343
|
|
|
6104
6344
|
${BOLD}Skills${RESET} ${GRAY}(Claude Code 슬래시 커맨드)${RESET}
|
|
6105
6345
|
|
|
6106
|
-
${AMBER}/tfx-auto${RESET} ${GRAY}자동 분류 + 병렬 실행 (--cli codex|
|
|
6346
|
+
${AMBER}/tfx-auto${RESET} ${GRAY}자동 분류 + 병렬 실행 (--cli codex|antigravity|claude, --parallel N|swarm)${RESET}
|
|
6107
6347
|
${AMBER}/tfx-setup${RESET} ${GRAY}HUD 설정 + 진단${RESET}
|
|
6108
6348
|
${YELLOW}/tfx-doctor${RESET} ${GRAY}진단 + 수리 + 캐시 초기화${RESET}
|
|
6109
6349
|
|
|
@@ -7013,6 +7253,10 @@ async function main() {
|
|
|
7013
7253
|
|
|
7014
7254
|
switch (cmd) {
|
|
7015
7255
|
case "auto": {
|
|
7256
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7257
|
+
printCommandHelp("auto");
|
|
7258
|
+
return;
|
|
7259
|
+
}
|
|
7016
7260
|
const parsedArgs = parseRouteArgs(cmdArgs);
|
|
7017
7261
|
const decision = applyAutoDispatchDecision(parsedArgs);
|
|
7018
7262
|
if (JSON_OUTPUT) {
|
|
@@ -7023,12 +7267,20 @@ async function main() {
|
|
|
7023
7267
|
return;
|
|
7024
7268
|
}
|
|
7025
7269
|
case "setup":
|
|
7270
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7271
|
+
printCommandHelp("setup");
|
|
7272
|
+
return;
|
|
7273
|
+
}
|
|
7026
7274
|
cmdSetup({
|
|
7027
7275
|
dryRun: cmdArgs.includes("--dry-run"),
|
|
7028
7276
|
enableHubAutostart: cmdArgs.includes("--enable-hub-autostart"),
|
|
7029
7277
|
});
|
|
7030
7278
|
return;
|
|
7031
7279
|
case "doctor": {
|
|
7280
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7281
|
+
printCommandHelp("doctor");
|
|
7282
|
+
return;
|
|
7283
|
+
}
|
|
7032
7284
|
if (cmdArgs.includes("--audit")) {
|
|
7033
7285
|
const auditScript = join(PKG_ROOT, "scripts", "config-audit.mjs");
|
|
7034
7286
|
const auditArgs = JSON_OUTPUT ? ["--json"] : [];
|
|
@@ -7156,28 +7408,44 @@ async function main() {
|
|
|
7156
7408
|
cmdSchema(cmdArgs);
|
|
7157
7409
|
return;
|
|
7158
7410
|
case "update":
|
|
7159
|
-
await cmdUpdate();
|
|
7411
|
+
await cmdUpdate(cmdArgs);
|
|
7160
7412
|
return;
|
|
7161
7413
|
case "list":
|
|
7162
7414
|
case "ls":
|
|
7415
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7416
|
+
printCommandHelp("list");
|
|
7417
|
+
return;
|
|
7418
|
+
}
|
|
7163
7419
|
cmdList({ json: JSON_OUTPUT });
|
|
7164
7420
|
return;
|
|
7165
7421
|
case "handoff":
|
|
7166
7422
|
cmdHandoff(cmdArgs, { json: JSON_OUTPUT });
|
|
7167
7423
|
return;
|
|
7168
7424
|
case "hub":
|
|
7425
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7426
|
+
printCommandHelp("hub");
|
|
7427
|
+
return;
|
|
7428
|
+
}
|
|
7169
7429
|
await cmdHub(cmdArgs, {
|
|
7170
7430
|
json:
|
|
7171
7431
|
JSON_OUTPUT && ["status", "ensure"].includes(cmdArgs[0] || "status"),
|
|
7172
7432
|
});
|
|
7173
7433
|
return;
|
|
7174
7434
|
case "monitor": {
|
|
7435
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7436
|
+
printCommandHelp("monitor");
|
|
7437
|
+
return;
|
|
7438
|
+
}
|
|
7175
7439
|
const { createMonitor } = await import("../tui/monitor.mjs");
|
|
7176
7440
|
const mon = createMonitor();
|
|
7177
7441
|
await mon.start();
|
|
7178
7442
|
break;
|
|
7179
7443
|
}
|
|
7180
7444
|
case "tray": {
|
|
7445
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7446
|
+
printCommandHelp("tray");
|
|
7447
|
+
return;
|
|
7448
|
+
}
|
|
7181
7449
|
const trayUrl = new URL("../hub/tray.mjs", import.meta.url);
|
|
7182
7450
|
const trayPath = fileURLToPath(trayUrl);
|
|
7183
7451
|
if (cmdArgs.includes("--attach")) {
|
|
@@ -7200,6 +7468,10 @@ async function main() {
|
|
|
7200
7468
|
}
|
|
7201
7469
|
case "multi": {
|
|
7202
7470
|
const subcommand = cmdArgs[0] || "";
|
|
7471
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7472
|
+
printCommandHelp("multi");
|
|
7473
|
+
return;
|
|
7474
|
+
}
|
|
7203
7475
|
if (JSON_OUTPUT) process.env.TFX_OUTPUT_JSON = "1";
|
|
7204
7476
|
else delete process.env.TFX_OUTPUT_JSON;
|
|
7205
7477
|
if (subcommand !== "status") {
|
|
@@ -7220,6 +7492,10 @@ async function main() {
|
|
|
7220
7492
|
return;
|
|
7221
7493
|
}
|
|
7222
7494
|
case "codex-team":
|
|
7495
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7496
|
+
await cmdCodexTeam(["--help"]);
|
|
7497
|
+
return;
|
|
7498
|
+
}
|
|
7223
7499
|
if (JSON_OUTPUT) process.env.TFX_OUTPUT_JSON = "1";
|
|
7224
7500
|
else delete process.env.TFX_OUTPUT_JSON;
|
|
7225
7501
|
await checkHubRunning();
|
|
@@ -7231,6 +7507,10 @@ async function main() {
|
|
|
7231
7507
|
return;
|
|
7232
7508
|
case "notion-read":
|
|
7233
7509
|
case "nr": {
|
|
7510
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7511
|
+
printCommandHelp("notion-read");
|
|
7512
|
+
return;
|
|
7513
|
+
}
|
|
7234
7514
|
const scriptPath = join(PKG_ROOT, "scripts", "notion-read.mjs");
|
|
7235
7515
|
try {
|
|
7236
7516
|
execFileSync(process.execPath, [scriptPath, ...cmdArgs], {
|
|
@@ -7247,6 +7527,10 @@ async function main() {
|
|
|
7247
7527
|
return;
|
|
7248
7528
|
}
|
|
7249
7529
|
case "hooks": {
|
|
7530
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7531
|
+
printCommandHelp("hooks");
|
|
7532
|
+
return;
|
|
7533
|
+
}
|
|
7250
7534
|
const hookManagerPath = join(PKG_ROOT, "hooks", "hook-manager.mjs");
|
|
7251
7535
|
const sub = cmdArgs[0] || "status";
|
|
7252
7536
|
try {
|
|
@@ -7267,6 +7551,10 @@ async function main() {
|
|
|
7267
7551
|
case "synapse": {
|
|
7268
7552
|
const { cmdSynapseStatus } = await import("../hub/team/synapse-cli.mjs");
|
|
7269
7553
|
const sub = cmdArgs[0] || "status";
|
|
7554
|
+
if (isHelpArg(sub)) {
|
|
7555
|
+
printCommandHelp("synapse");
|
|
7556
|
+
return;
|
|
7557
|
+
}
|
|
7270
7558
|
if (sub !== "status") {
|
|
7271
7559
|
throw createCliError(`synapse 서브커맨드 미지원: ${sub}`, {
|
|
7272
7560
|
exitCode: EXIT_ARG_ERROR,
|
|
@@ -7278,6 +7566,10 @@ async function main() {
|
|
|
7278
7566
|
return;
|
|
7279
7567
|
}
|
|
7280
7568
|
case "review": {
|
|
7569
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7570
|
+
printCommandHelp("review");
|
|
7571
|
+
return;
|
|
7572
|
+
}
|
|
7281
7573
|
const ref =
|
|
7282
7574
|
cmdArgs[0] && !cmdArgs[0].startsWith("--") ? cmdArgs[0] : "HEAD";
|
|
7283
7575
|
const baseIdx = cmdArgs.indexOf("--base");
|
|
@@ -7397,6 +7689,10 @@ ${s.options.map((o) => ` ${DIM}${o.name.padEnd(16)}${RESET} ${GRAY}${o.descri
|
|
|
7397
7689
|
return;
|
|
7398
7690
|
}
|
|
7399
7691
|
case "why": {
|
|
7692
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7693
|
+
printCommandHelp("why");
|
|
7694
|
+
return;
|
|
7695
|
+
}
|
|
7400
7696
|
const { cmdSynapseWhy } = await import("../hub/team/synapse-cli.mjs");
|
|
7401
7697
|
await cmdSynapseWhy(cmdArgs, { json: JSON_OUTPUT });
|
|
7402
7698
|
return;
|
|
@@ -7404,6 +7700,10 @@ ${s.options.map((o) => ` ${DIM}${o.name.padEnd(16)}${RESET} ${GRAY}${o.descri
|
|
|
7404
7700
|
case "version":
|
|
7405
7701
|
case "--version":
|
|
7406
7702
|
case "-v":
|
|
7703
|
+
if (cmdArgs.some(isHelpArg)) {
|
|
7704
|
+
printCommandHelp("version");
|
|
7705
|
+
return;
|
|
7706
|
+
}
|
|
7407
7707
|
cmdVersion({ json: JSON_OUTPUT });
|
|
7408
7708
|
return;
|
|
7409
7709
|
case "help":
|
package/config/mcp-registry.json
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"hub_base": "http://127.0.0.1:27888"
|
|
8
8
|
},
|
|
9
9
|
"policy_notes": {
|
|
10
|
-
"policy": "Server policy is the SSOT for client sync shape: hosted writes url+headers, gateway-sse writes http://127.0.0.1:81XX/sse with SSE metadata, and stdio writes command/args/env.",
|
|
11
|
-
"transport": "Server transport accepts \"hub-url\" for triflux Hub URL flow, \"http\" for direct Streamable HTTP MCP endpoints, or \"stdio\" for upstream-stdio-only MCP servers. Gateway-backed stdio upstreams use policy:\"gateway-
|
|
10
|
+
"policy": "Server policy is the SSOT for client sync shape: hosted writes url+headers, gateway-sse writes http://127.0.0.1:81XX/sse with SSE metadata, gateway-http writes http://127.0.0.1:81XX/mcp with HTTP metadata, and stdio writes command/args/env.",
|
|
11
|
+
"transport": "Server transport accepts \"hub-url\" for triflux Hub URL flow, \"http\" for direct Streamable HTTP MCP endpoints, or \"stdio\" for upstream-stdio-only MCP servers. Gateway-backed stdio upstreams should use policy:\"gateway-http\" plus gateway_port/gateway_path so clients receive reconnect-safe HTTP MCP config; legacy policy:\"gateway-sse\" remains supported only for backward compatibility.",
|
|
12
12
|
"headers": "Optional headers are allowed only for HTTP-compatible transports. Each header value must be a descriptor: {\"value\":\"literal\"} for non-secret static values, {\"env\":\"ENV_VAR_NAME\"} for secrets resolved at sync/runtime, or {\"env\":\"ENV_VAR_NAME\",\"prefix\":\"Bearer \"} for common authorization formats.",
|
|
13
13
|
"secret_safety": "Resolved secret values must not be written back to this registry file. Missing env vars warn during sync and do not emit empty secret headers.",
|
|
14
14
|
"sync_denylist": "Array of client:server strings skipped by proactive registry sync, for example gemini:tfx-hub."
|
|
@@ -42,18 +42,22 @@
|
|
|
42
42
|
"description": "Exa neural/semantic web search — 학술/기술 깊이. Key 발급: https://exa.ai/dashboard → secrets.env의 EXA_API_KEY"
|
|
43
43
|
},
|
|
44
44
|
"serena": {
|
|
45
|
-
"policy": "gateway-
|
|
45
|
+
"policy": "gateway-http",
|
|
46
|
+
"transport": "http",
|
|
46
47
|
"gateway_port": 8105,
|
|
48
|
+
"gateway_path": "/mcp",
|
|
47
49
|
"safe": true,
|
|
48
50
|
"targets": ["claude", "gemini", "codex", "antigravity"],
|
|
49
|
-
"description": "Serena MCP — supergateway
|
|
51
|
+
"description": "Serena MCP — local supergateway stateful Streamable HTTP endpoint (:8105/mcp)"
|
|
50
52
|
},
|
|
51
53
|
"brave-search": {
|
|
52
|
-
"policy": "gateway-
|
|
54
|
+
"policy": "gateway-http",
|
|
55
|
+
"transport": "http",
|
|
53
56
|
"gateway_port": 8101,
|
|
57
|
+
"gateway_path": "/mcp",
|
|
54
58
|
"safe": true,
|
|
55
59
|
"targets": ["claude", "gemini", "codex", "antigravity"],
|
|
56
|
-
"description": "Brave Search MCP — supergateway
|
|
60
|
+
"description": "Brave Search MCP — local supergateway stateful Streamable HTTP endpoint (:8101/mcp). BRAVE_API_KEY 환경변수 필요 (https://brave.com/search/api/). secrets.env 의 BRAVE_API_KEY 참조."
|
|
57
61
|
},
|
|
58
62
|
"tavily": {
|
|
59
63
|
"policy": "hosted",
|