triflux 3.2.0-dev.7 → 3.2.0-dev.8

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 (2) hide show
  1. package/bin/triflux.mjs +89 -24
  2. package/package.json +1 -1
package/bin/triflux.mjs CHANGED
@@ -684,7 +684,7 @@ function cmdDoctor(options = {}) {
684
684
  function cmdUpdate() {
685
685
  const isDev = isDevUpdateRequested(process.argv);
686
686
  const tagLabel = isDev ? ` ${YELLOW}--dev${RESET}` : "";
687
- console.log(`\n${BOLD}triflux update${RESET}${tagLabel}\n`);
687
+ console.log(`\n${BOLD}triflux update${RESET}${tagLabel}\n`);
688
688
 
689
689
  // 1. 설치 방식 감지
690
690
  const pluginsFile = join(CLAUDE_DIR, "plugins", "installed_plugins.json");
@@ -736,12 +736,13 @@ function cmdUpdate() {
736
736
 
737
737
  info(`검색: ${installMode === "plugin" ? "플러그인" : installMode === "npm-global" ? "npm global" : installMode === "npm-local" ? "npm local" : installMode === "git-local" ? "git 로컬 저장소" : "알 수 없음"} 설치 감지`);
738
738
 
739
- // 2. 설치 방식에 따라 업데이트
740
- const oldVer = PKG.version;
741
- let updated = false;
742
-
743
- try {
744
- switch (installMode) {
739
+ // 2. 설치 방식에 따라 업데이트
740
+ const oldVer = PKG.version;
741
+ let updated = false;
742
+ let stoppedHubInfo = null;
743
+
744
+ try {
745
+ switch (installMode) {
745
746
  case "plugin": {
746
747
  const gitDir = pluginPath || PKG_ROOT;
747
748
  const result = execSync("git pull", {
@@ -752,11 +753,15 @@ function cmdUpdate() {
752
753
  ok(`git pull — ${result}`);
753
754
  updated = true;
754
755
  break;
755
- }
756
- case "npm-global": {
757
- const npmCmd = isDev ? "npm install -g triflux@dev" : "npm update -g triflux";
758
- const result = execSync(npmCmd, {
759
- encoding: "utf8",
756
+ }
757
+ case "npm-global": {
758
+ stoppedHubInfo = stopHubForUpdate();
759
+ if (stoppedHubInfo?.pid) {
760
+ info(`실행 중 hub 정지 (PID ${stoppedHubInfo.pid})`);
761
+ }
762
+ const npmCmd = isDev ? "npm install -g triflux@dev" : "npm update -g triflux";
763
+ const result = execSync(npmCmd, {
764
+ encoding: "utf8",
760
765
  timeout: 60000,
761
766
  stdio: ["pipe", "pipe", "ignore"],
762
767
  }).trim().split(/\r?\n/)[0];
@@ -790,11 +795,14 @@ function cmdUpdate() {
790
795
  fail("설치 방식을 감지할 수 없음");
791
796
  info("수동 업데이트: cd <triflux-dir> && git pull");
792
797
  return;
793
- }
794
- } catch (e) {
795
- fail(`업데이트 실패: ${e.message}`);
796
- return;
797
- }
798
+ }
799
+ } catch (e) {
800
+ if (stoppedHubInfo && startHubAfterUpdate(stoppedHubInfo)) {
801
+ info("업데이트 실패 후 hub 재기동 시도");
802
+ }
803
+ fail(`업데이트 실패: ${e.message}`);
804
+ return;
805
+ }
798
806
 
799
807
  // 3. setup 재실행 (tfx-route.sh, HUD, 스킬 동기화)
800
808
  if (updated) {
@@ -812,11 +820,16 @@ function cmdUpdate() {
812
820
  ok(`버전: v${oldVer} (이미 최신)`);
813
821
  }
814
822
 
815
- // setup 재실행
816
- console.log("");
817
- info("setup 재실행 중...");
818
- cmdSetup();
819
- }
823
+ // setup 재실행
824
+ console.log("");
825
+ info("setup 재실행 중...");
826
+ cmdSetup();
827
+
828
+ if (stoppedHubInfo) {
829
+ if (startHubAfterUpdate(stoppedHubInfo)) info("hub 재기동 완료");
830
+ else warn("hub 재기동 실패 — `tfx hub start`로 수동 시작 필요");
831
+ }
832
+ }
820
833
 
821
834
  console.log(`${GREEN}${BOLD}업데이트 완료${RESET}\n`);
822
835
  }
@@ -994,8 +1007,60 @@ async function cmdCodexTeam() {
994
1007
 
995
1008
  // ── hub 서브커맨드 ──
996
1009
 
997
- const HUB_PID_DIR = join(homedir(), ".claude", "cache", "tfx-hub");
998
- const HUB_PID_FILE = join(HUB_PID_DIR, "hub.pid");
1010
+ const HUB_PID_DIR = join(homedir(), ".claude", "cache", "tfx-hub");
1011
+ const HUB_PID_FILE = join(HUB_PID_DIR, "hub.pid");
1012
+
1013
+ function sleepMs(ms) {
1014
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
1015
+ }
1016
+
1017
+ function stopHubForUpdate() {
1018
+ if (!existsSync(HUB_PID_FILE)) return null;
1019
+ let info = null;
1020
+ try {
1021
+ info = JSON.parse(readFileSync(HUB_PID_FILE, "utf8"));
1022
+ process.kill(info.pid, 0);
1023
+ } catch {
1024
+ try { unlinkSync(HUB_PID_FILE); } catch {}
1025
+ return null;
1026
+ }
1027
+
1028
+ try {
1029
+ if (process.platform === "win32") {
1030
+ execSync(`taskkill /PID ${info.pid} /T /F`, {
1031
+ stdio: ["pipe", "pipe", "ignore"],
1032
+ timeout: 10000,
1033
+ });
1034
+ } else {
1035
+ process.kill(info.pid, "SIGTERM");
1036
+ }
1037
+ } catch {
1038
+ try { process.kill(info.pid, "SIGKILL"); } catch {}
1039
+ }
1040
+
1041
+ sleepMs(300);
1042
+ try { unlinkSync(HUB_PID_FILE); } catch {}
1043
+ return info;
1044
+ }
1045
+
1046
+ function startHubAfterUpdate(info) {
1047
+ if (!info) return false;
1048
+ const serverPath = join(PKG_ROOT, "hub", "server.mjs");
1049
+ if (!existsSync(serverPath)) return false;
1050
+ const port = Number(info?.port) > 0 ? String(info.port) : String(process.env.TFX_HUB_PORT || "27888");
1051
+
1052
+ try {
1053
+ const child = spawn(process.execPath, [serverPath], {
1054
+ env: { ...process.env, TFX_HUB_PORT: port },
1055
+ stdio: "ignore",
1056
+ detached: true,
1057
+ });
1058
+ child.unref();
1059
+ return true;
1060
+ } catch {
1061
+ return false;
1062
+ }
1063
+ }
999
1064
 
1000
1065
  // 설치된 CLI에 tfx-hub MCP 서버 자동 등록 (1회 설정, 이후 재실행 불필요)
1001
1066
  function autoRegisterMcp(mcpUrl) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "3.2.0-dev.7",
3
+ "version": "3.2.0-dev.8",
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": {