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 +8 -3
- package/bin/triflux.mjs +98 -9
- package/hub/server.mjs +3 -2
- package/package.json +1 -1
package/.mcp.json
CHANGED
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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}${
|
|
884
|
-
console.log(` PID: ${
|
|
885
|
-
console.log(` DB: ${DIM}${HUB_PID_DIR}/state.db${RESET}
|
|
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}"
|
|
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
|
-
|
|
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
|
-
|
|
84
|
+
CallToolRequestSchema,
|
|
84
85
|
async (request) => {
|
|
85
86
|
const { name, arguments: args } = request.params;
|
|
86
87
|
const tool = tools.find(t => t.name === name);
|