triflux 3.1.0-dev.1 → 3.1.0-dev.2

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/.mcp.json CHANGED
@@ -1,3 +1,8 @@
1
- {
2
- "mcpServers": {}
3
- }
1
+ {
2
+ "mcpServers": {
3
+ "tfx-hub": {
4
+ "type": "url",
5
+ "url": "http://127.0.0.1:27888/mcp"
6
+ }
7
+ }
8
+ }
package/bin/triflux.mjs CHANGED
@@ -221,6 +221,13 @@ function cmdSetup() {
221
221
  }
222
222
  }
223
223
 
224
+ // hub MCP 사전 등록 (서버 미실행이어도 설정만 등록 — hub start 시 즉시 사용 가능)
225
+ if (existsSync(join(PKG_ROOT, "hub", "server.mjs"))) {
226
+ const defaultHubUrl = `http://127.0.0.1:${process.env.TFX_HUB_PORT || "27888"}/mcp`;
227
+ autoRegisterMcp(defaultHubUrl);
228
+ console.log("");
229
+ }
230
+
224
231
  // HUD statusLine 설정
225
232
  console.log(`${CYAN}[HUD 설정]${RESET}`);
226
233
  const settingsPath = join(CLAUDE_DIR, "settings.json");
@@ -578,7 +585,9 @@ function cmdDoctor(options = {}) {
578
585
  }
579
586
 
580
587
  function cmdUpdate() {
581
- console.log(`\n${BOLD}triflux update${RESET}\n`);
588
+ const isDev = process.argv.includes("--dev");
589
+ const tagLabel = isDev ? ` ${YELLOW}@dev${RESET}` : "";
590
+ console.log(`\n${BOLD}triflux update${RESET}${tagLabel}\n`);
582
591
 
583
592
  // 1. 설치 방식 감지
584
593
  const pluginsFile = join(CLAUDE_DIR, "plugins", "installed_plugins.json");
@@ -648,17 +657,19 @@ function cmdUpdate() {
648
657
  break;
649
658
  }
650
659
  case "npm-global": {
651
- const result = execSync("npm update -g triflux", {
660
+ const npmCmd = isDev ? "npm install -g triflux@dev" : "npm update -g triflux";
661
+ const result = execSync(npmCmd, {
652
662
  encoding: "utf8",
653
663
  timeout: 60000,
654
664
  stdio: ["pipe", "pipe", "ignore"],
655
665
  }).trim().split(/\r?\n/)[0];
656
- ok(`npm update -g — ${result || "완료"}`);
666
+ ok(`${isDev ? "npm install -g @dev" : "npm update -g"} — ${result || "완료"}`);
657
667
  updated = true;
658
668
  break;
659
669
  }
660
670
  case "npm-local": {
661
- const result = execSync("npm update triflux", {
671
+ const npmLocalCmd = isDev ? "npm install triflux@dev" : "npm update triflux";
672
+ const result = execSync(npmLocalCmd, {
662
673
  encoding: "utf8",
663
674
  timeout: 60000,
664
675
  cwd: process.cwd(),
@@ -812,6 +823,7 @@ ${updateNotice}
812
823
  ${DIM} --fix${RESET} ${GRAY}진단 + 자동 수정${RESET}
813
824
  ${DIM} --reset${RESET} ${GRAY}캐시 전체 초기화${RESET}
814
825
  ${WHITE_BRIGHT}tfx update${RESET} ${GRAY}최신 버전으로 업데이트${RESET}
826
+ ${DIM} --dev${RESET} ${GRAY}dev 태그로 업데이트${RESET}
815
827
  ${WHITE_BRIGHT}tfx list${RESET} ${GRAY}설치된 스킬 목록${RESET}
816
828
  ${WHITE_BRIGHT}tfx hub${RESET} ${GRAY}MCP 메시지 버스 관리 (start/stop/status)${RESET}
817
829
  ${WHITE_BRIGHT}tfx notion-read${RESET} ${GRAY}Notion 페이지 → 마크다운 (Codex/Gemini MCP)${RESET}
@@ -835,6 +847,80 @@ ${updateNotice}
835
847
  const HUB_PID_DIR = join(homedir(), ".claude", "cache", "tfx-hub");
836
848
  const HUB_PID_FILE = join(HUB_PID_DIR, "hub.pid");
837
849
 
850
+ // 설치된 CLI에 tfx-hub MCP 서버 자동 등록 (1회 설정, 이후 재실행 불필요)
851
+ function autoRegisterMcp(mcpUrl) {
852
+ section("MCP 자동 등록");
853
+
854
+ // Codex — codex mcp add
855
+ if (which("codex")) {
856
+ try {
857
+ // 이미 등록됐는지 확인
858
+ const list = execSync("codex mcp list 2>&1", { encoding: "utf8", timeout: 10000, stdio: ["pipe", "pipe", "pipe"] });
859
+ if (list.includes("tfx-hub")) {
860
+ ok("Codex: 이미 등록됨");
861
+ } else {
862
+ execSync(`codex mcp add tfx-hub --url ${mcpUrl}`, { timeout: 10000, stdio: "ignore" });
863
+ ok("Codex: MCP 등록 완료");
864
+ }
865
+ } catch {
866
+ // mcp list/add 미지원 → 설정 파일 직접 수정
867
+ try {
868
+ const codexDir = join(homedir(), ".codex");
869
+ const configFile = join(codexDir, "config.json");
870
+ let config = {};
871
+ if (existsSync(configFile)) config = JSON.parse(readFileSync(configFile, "utf8"));
872
+ if (!config.mcpServers) config.mcpServers = {};
873
+ if (!config.mcpServers["tfx-hub"]) {
874
+ config.mcpServers["tfx-hub"] = { url: mcpUrl };
875
+ if (!existsSync(codexDir)) mkdirSync(codexDir, { recursive: true });
876
+ writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n");
877
+ ok("Codex: config.json에 등록 완료");
878
+ } else {
879
+ ok("Codex: 이미 등록됨");
880
+ }
881
+ } catch (e) { warn(`Codex 등록 실패: ${e.message}`); }
882
+ }
883
+ } else {
884
+ info("Codex: 미설치 (건너뜀)");
885
+ }
886
+
887
+ // Gemini — settings.json 직접 수정
888
+ if (which("gemini")) {
889
+ try {
890
+ const geminiDir = join(homedir(), ".gemini");
891
+ const settingsFile = join(geminiDir, "settings.json");
892
+ let settings = {};
893
+ if (existsSync(settingsFile)) settings = JSON.parse(readFileSync(settingsFile, "utf8"));
894
+ if (!settings.mcpServers) settings.mcpServers = {};
895
+ if (!settings.mcpServers["tfx-hub"]) {
896
+ settings.mcpServers["tfx-hub"] = { url: mcpUrl };
897
+ if (!existsSync(geminiDir)) mkdirSync(geminiDir, { recursive: true });
898
+ writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + "\n");
899
+ ok("Gemini: settings.json에 등록 완료");
900
+ } else {
901
+ ok("Gemini: 이미 등록됨");
902
+ }
903
+ } catch (e) { warn(`Gemini 등록 실패: ${e.message}`); }
904
+ } else {
905
+ info("Gemini: 미설치 (건너뜀)");
906
+ }
907
+
908
+ // Claude — 프로젝트 .mcp.json에 등록 (오케스트레이터용)
909
+ try {
910
+ const mcpJsonPath = join(PKG_ROOT, ".mcp.json");
911
+ let mcpJson = {};
912
+ if (existsSync(mcpJsonPath)) mcpJson = JSON.parse(readFileSync(mcpJsonPath, "utf8"));
913
+ if (!mcpJson.mcpServers) mcpJson.mcpServers = {};
914
+ if (!mcpJson.mcpServers["tfx-hub"]) {
915
+ mcpJson.mcpServers["tfx-hub"] = { type: "url", url: mcpUrl };
916
+ writeFileSync(mcpJsonPath, JSON.stringify(mcpJson, null, 2) + "\n");
917
+ ok("Claude: .mcp.json에 등록 완료");
918
+ } else {
919
+ ok("Claude: 이미 등록됨");
920
+ }
921
+ } catch (e) { warn(`Claude 등록 실패: ${e.message}`); }
922
+ }
923
+
838
924
  function cmdHub() {
839
925
  const sub = process.argv[3] || "status";
840
926
 
@@ -878,11 +964,14 @@ function cmdHub() {
878
964
  }
879
965
 
880
966
  if (started) {
881
- const info = JSON.parse(readFileSync(HUB_PID_FILE, "utf8"));
967
+ const hubInfo = JSON.parse(readFileSync(HUB_PID_FILE, "utf8"));
882
968
  console.log(`\n ${GREEN_BRIGHT}✓${RESET} ${BOLD}tfx-hub 시작${RESET}`);
883
- console.log(` URL: ${AMBER}${info.url}${RESET}`);
884
- console.log(` PID: ${info.pid}`);
885
- console.log(` DB: ${DIM}${HUB_PID_DIR}/state.db${RESET}\n`);
969
+ console.log(` URL: ${AMBER}${hubInfo.url}${RESET}`);
970
+ console.log(` PID: ${hubInfo.pid}`);
971
+ console.log(` DB: ${DIM}${HUB_PID_DIR}/state.db${RESET}`);
972
+ console.log("");
973
+ autoRegisterMcp(hubInfo.url);
974
+ console.log("");
886
975
  } else {
887
976
  // 직접 포그라운드 모드로 안내
888
977
  console.log(`\n ${YELLOW}⚠${RESET} 백그라운드 시작 실패 — 포그라운드로 실행:`);
@@ -929,7 +1018,7 @@ function cmdHub() {
929
1018
  // HTTP 상태 조회 시도
930
1019
  try {
931
1020
  const statusUrl = info.url.replace("/mcp", "/status");
932
- const result = execSync(`curl -s "${statusUrl}" 2>/dev/null`, { encoding: "utf8", timeout: 3000 });
1021
+ const result = execSync(`curl -s "${statusUrl}"`, { encoding: "utf8", timeout: 3000, stdio: ["pipe", "pipe", "ignore"] });
933
1022
  const data = JSON.parse(result);
934
1023
  if (data.hub) {
935
1024
  console.log(` State: ${data.hub.state}`);
package/hub/server.mjs CHANGED
@@ -8,6 +8,7 @@ import { writeFileSync, unlinkSync, existsSync, mkdirSync, readFileSync } from '
8
8
 
9
9
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
10
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
11
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
11
12
 
12
13
  import { createStore } from './store.mjs';
13
14
  import { createRouter } from './router.mjs';
@@ -68,7 +69,7 @@ export async function startHub({ port = 27888, dbPath, host = '127.0.0.1' } = {}
68
69
 
69
70
  // tools/list 핸들러
70
71
  mcp.setRequestHandler(
71
- { method: 'tools/list' },
72
+ ListToolsRequestSchema,
72
73
  async () => ({
73
74
  tools: tools.map(t => ({
74
75
  name: t.name,
@@ -80,7 +81,7 @@ export async function startHub({ port = 27888, dbPath, host = '127.0.0.1' } = {}
80
81
 
81
82
  // tools/call 핸들러
82
83
  mcp.setRequestHandler(
83
- { method: 'tools/call' },
84
+ CallToolRequestSchema,
84
85
  async (request) => {
85
86
  const { name, arguments: args } = request.params;
86
87
  const tool = tools.find(t => t.name === name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "3.1.0-dev.1",
3
+ "version": "3.1.0-dev.2",
4
4
  "description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Gemini, and Claude",
5
5
  "type": "module",
6
6
  "bin": {