triflux 9.0.0 → 9.2.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 CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  <p align="center">
12
12
  <strong>Consensus Intelligence 기반 Tri-CLI 오케스트레이션</strong><br>
13
- <em>Claude + Codex + Gemini — 3자 토론, Anti-Herding 검증, Deep/Light 변형을 갖춘 35개 스킬.</em>
13
+ <em>Claude + Codex + Gemini — 자연어 라우팅, 교차 모델 리뷰, Deep/Light 변형을 갖춘 38개 스킬.</em>
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -27,7 +27,7 @@
27
27
  <p align="center">
28
28
  <a href="#빠른-시작">빠른 시작</a> ·
29
29
  <a href="#tri-cli-합의-엔진">Tri-CLI 합의 엔진</a> ·
30
- <a href="#35개-스킬">35개 스킬</a> ·
30
+ <a href="#38개-스킬">38개 스킬</a> ·
31
31
  <a href="#아키텍처">아키텍처</a> ·
32
32
  <a href="#deep-vs-light">Deep vs Light</a> ·
33
33
  <a href="#보안">보안</a>
@@ -80,21 +80,26 @@ tfx setup
80
80
 
81
81
  ---
82
82
 
83
- ## v8의 새로운 기능
83
+ ## v9의 새로운 기능
84
84
 
85
- **triflux v8**은 **Tri-CLI Consensus Intelligence**를 도입합니다. Claude, Codex, Gemini가 각각 독립적으로 분석한 뒤, 구조화된 토론을 거쳐 교차 검증하는 근본적으로 새로운 접근 방식입니다. 모든 Deep 스킬은 Anti-Herding(편향 오염 방지)과 Consensus Gate통한 출력 보장을 제공합니다.
85
+ **triflux v9**은 **하네스 네이티브 인텔리전스**를 도입합니다. 자연어로 말하면 적절한 스킬로 자동 라우팅되고, 교차 모델 리뷰로 동일 모델의 self-approve차단합니다.
86
86
 
87
- ### 주요 특징
87
+ ### v9 주요 특징
88
+
89
+ - **자연어 라우팅** — "리뷰해줘"라고 말하면 `/tfx-review`가 자동 호출. "제대로/꼼꼼히" 수정자로 Deep 변형 자동 에스컬레이션
90
+ - **교차 모델 리뷰** — Claude가 작성하면 Codex가 리뷰, Codex가 작성하면 Claude가 리뷰. 동일 모델 self-approve 차단. 커밋 전 미검증 파일 nudge
91
+ - **맥락 격리** — 현재 맥락과 무관한 요청을 감지하면 별도 psmux 세션으로 분리 제안
92
+ - **38개 스킬** — Light 14개 + Deep 10개 + Infrastructure 14개, 10개 도메인으로 구성
93
+ - **Codex Swarm 강화** — PowerShell `.ps1` 런처, 프로파일 기반 실행, `/merge-worktree`로 결과 자동 수집
94
+ - **스킬 메타데이터** — 모든 스킬에 래퍼/인프라/Light-Deep 관계 표기. 트리거 충돌 해소
95
+
96
+ ### v8 기반 (계속 유지)
88
97
 
89
- - **35개 스킬** — Light 11개 + Deep 10개 + Infrastructure 12개, 9개 도메인으로 구성
90
98
  - **Tri-Debate Engine** — 3개 CLI가 독립 분석 후 Anti-Herding, 교차 검증, 합의 점수 산출
91
99
  - **Deep/Light 변형** — 모든 기능에 토큰 효율적인 Light 모드와 정밀한 Deep 모드를 제공
92
- - **Consensus Gate** — Deep 스킬은 3개 CLI 중 2개 이상의 동의를 요구하며, 학습된 가중치로 CLI 신뢰도를 추적
93
- - **Anti-Herding** — 1라운드는 상호 참조 없이 병렬 실행하여 편향 오염을 원천 차단
94
- - **Expert Panel** — `tfx-panel`을 통한 가상 전문가 시뮬레이션 (Fowler, Newman, Porter 등)
95
- - **94% 토큰 절감** — `tfx-index`가 58K 토큰 분량의 파일 읽기를 3KB 프로젝트 맵으로 대체
96
- - **Persistence Loop** — `tfx-persist`(정식 이름, 3자 검증), `/tfx-ralph`(호환 별칭), `tfx-sisyphus`(자동 라우팅)가 검증 완료까지 반복 실행
97
- - **Hub IPC** — Named Pipe 및 HTTP MCP 브리지를 활용한 초고속 상주형 Hub 서버
100
+ - **Consensus Gate** — Deep 스킬은 3개 CLI 중 2개 이상의 동의 요구
101
+ - **Expert Panel** — `tfx-panel`을 통한 가상 전문가 시뮬레이션
102
+ - **Hub IPC** — Named Pipe HTTP MCP 브리지를 활용한 상주형 Hub 서버
98
103
  - **psmux / Windows 네이티브** — `tmux`(WSL)와 `psmux`(Windows Terminal) 하이브리드 지원
99
104
 
100
105
  ---
@@ -128,7 +133,7 @@ Phase 3: Resolution (합의율 < 70%일 경우)
128
133
 
129
134
  ---
130
135
 
131
- ## 35개 스킬
136
+ ## 38개 스킬
132
137
 
133
138
  ### 리서치
134
139
 
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  <p align="center">
12
12
  <strong>Tri-CLI Orchestration with Consensus Intelligence</strong><br>
13
- <em>Claude + Codex + Gemini — 3-party debate, anti-herding verification, and 35 skills with Deep/Light variants.</em>
13
+ <em>Claude + Codex + Gemini — natural language routing, cross-model review, 38 skills with Deep/Light variants.</em>
14
14
  </p>
15
15
 
16
16
  <p align="center">
@@ -27,7 +27,7 @@
27
27
  <p align="center">
28
28
  <a href="#quick-start">Quick Start</a> ·
29
29
  <a href="#tri-cli-consensus">Tri-CLI Consensus</a> ·
30
- <a href="#35-skills">35 Skills</a> ·
30
+ <a href="#38-skills">38 Skills</a> ·
31
31
  <a href="#architecture">Architecture</a> ·
32
32
  <a href="#deep-vs-light">Deep vs Light</a> ·
33
33
  <a href="#security">Security</a>
@@ -80,21 +80,26 @@ tfx setup
80
80
 
81
81
  ---
82
82
 
83
- ## What's New in v8
83
+ ## What's New in v9
84
84
 
85
- **triflux v8** introduces **Tri-CLI Consensus Intelligence** — a fundamentally new approach where Claude, Codex, and Gemini independently analyze, then cross-validate through structured debate. Every Deep skill guarantees anti-herding (no bias contamination) and consensus-gated output.
85
+ **triflux v9** introduces **Harness-Native Intelligence** — speak naturally, and triflux routes to the right skill automatically. Cross-model review ensures no model approves its own work.
86
86
 
87
- ### Highlights
87
+ ### v9 Highlights
88
+
89
+ - **Natural Language Routing** — Say "review this" or "리뷰해줘" instead of memorizing `/tfx-review`. Depth modifiers ("thoroughly", "제대로") auto-escalate to Deep variants
90
+ - **Cross-Model Review** — Claude writes → Codex reviews. Codex writes → Claude reviews. Same-model self-approve is blocked. Pre-commit nudge for unreviewed files
91
+ - **Context Isolation** — Off-topic requests auto-detected; spawns a clean psmux session so your main context stays focused
92
+ - **38 Skills** — 14 Light + 10 Deep + 14 Infrastructure, organized across 10 domains
93
+ - **Codex Swarm Hardened** — PowerShell `.ps1` launchers, profile-based execution (no `--dangerously` flag), `/merge-worktree` auto-invocation for result collection
94
+ - **Skill Metadata** — Every skill labeled: wrapper/infrastructure/Light-Deep pairs. Trigger conflicts resolved
95
+
96
+ ### v8 Foundations (carried forward)
88
97
 
89
- - **35 Skills** — 11 Light + 10 Deep + 12 Infrastructure, organized across 9 domains
90
98
  - **Tri-Debate Engine** — 3-CLI independent analysis with anti-herding, cross-validation, and consensus scoring
91
99
  - **Deep/Light Variants** — Every capability has a token-efficient Light mode and a thorough Deep mode
92
100
  - **Consensus Gate** — Deep skills require 2/3+ CLI agreement; learned weights track CLI reliability over time
93
- - **Anti-Herding** — Round 1 runs in parallel with zero cross-visibility to prevent bias contamination
94
- - **Expert Panel** — Virtual expert simulation (Fowler, Newman, Porter, etc.) via `tfx-panel`
95
- - **94% Token Reduction** — `tfx-index` creates a 3KB project map replacing 58K tokens of file reads
96
- - **Persistence Loops** — `tfx-persist` (canonical, 3-party verified), `/tfx-ralph` (compat alias), and `tfx-sisyphus` (auto-routing) run until verified complete
97
- - **Hub IPC** — Lightning-fast resident Hub server with Named Pipe & HTTP MCP bridge
101
+ - **Expert Panel** — Virtual expert simulation via `tfx-panel`
102
+ - **Hub IPC** — Resident Hub server with Named Pipe & HTTP MCP bridge
98
103
  - **psmux / Windows Native** — Hybrid support for `tmux` (WSL) and `psmux` (Windows Terminal)
99
104
 
100
105
  ---
@@ -128,7 +133,7 @@ Phase 3: Resolution (if consensus < 70%)
128
133
 
129
134
  ---
130
135
 
131
- ## 35 Skills
136
+ ## 38 Skills
132
137
 
133
138
  ### Research
134
139
 
package/bin/triflux.mjs CHANGED
@@ -16,8 +16,24 @@ const PKG_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
16
16
  const CLAUDE_DIR = join(homedir(), ".claude");
17
17
  const CODEX_DIR = join(homedir(), ".codex");
18
18
  const CODEX_CONFIG_PATH = join(CODEX_DIR, "config.toml");
19
+ const GEMINI_DIR = join(homedir(), ".gemini");
20
+ const GEMINI_PROFILES_PATH = join(GEMINI_DIR, "triflux-profiles.json");
19
21
  const PKG = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8"));
20
22
 
23
+ // 이 배열에 포함된 버전에서만 star prompt를 표시한다 (빈 배열 = 모든 버전에서 표시)
24
+ const STAR_PROMPT_VERSIONS = ["9.2.0"];
25
+
26
+ const DEFAULT_GEMINI_PROFILES = {
27
+ model: "gemini-3.1-pro-preview",
28
+ profiles: {
29
+ pro31: { model: "gemini-3.1-pro-preview", hint: "3.1 Pro — 플래그십 (1M ctx, 멀티모달)" },
30
+ flash3: { model: "gemini-3-flash-preview", hint: "3.0 Flash — 빠른 응답, 비용 효율" },
31
+ pro25: { model: "gemini-2.5-pro", hint: "2.5 Pro — 안정 (추론 강화)" },
32
+ flash25: { model: "gemini-2.5-flash", hint: "2.5 Flash — 경량 범용" },
33
+ lite25: { model: "gemini-2.5-flash-lite", hint: "2.5 Flash Lite — 최경량" },
34
+ },
35
+ };
36
+
21
37
  const REQUIRED_CODEX_PROFILES = [
22
38
  {
23
39
  name: "codex53_high",
@@ -496,6 +512,44 @@ function previewCodexProfiles() {
496
512
  };
497
513
  }
498
514
 
515
+ function ensureGeminiProfiles() {
516
+ try {
517
+ if (!existsSync(GEMINI_DIR)) mkdirSync(GEMINI_DIR, { recursive: true });
518
+
519
+ if (!existsSync(GEMINI_PROFILES_PATH)) {
520
+ writeFileSync(GEMINI_PROFILES_PATH, JSON.stringify(DEFAULT_GEMINI_PROFILES, null, 2) + "\n", "utf8");
521
+ return { ok: true, created: true, count: Object.keys(DEFAULT_GEMINI_PROFILES.profiles).length };
522
+ }
523
+
524
+ let cfg;
525
+ try {
526
+ cfg = JSON.parse(readFileSync(GEMINI_PROFILES_PATH, "utf8"));
527
+ } catch {
528
+ // 파싱 실패 → 재생성
529
+ writeFileSync(GEMINI_PROFILES_PATH, JSON.stringify(DEFAULT_GEMINI_PROFILES, null, 2) + "\n", "utf8");
530
+ return { ok: true, created: true, count: Object.keys(DEFAULT_GEMINI_PROFILES.profiles).length };
531
+ }
532
+
533
+ if (!cfg.profiles) cfg.profiles = {};
534
+ let added = 0;
535
+ for (const [name, value] of Object.entries(DEFAULT_GEMINI_PROFILES.profiles)) {
536
+ if (!cfg.profiles[name]) {
537
+ cfg.profiles[name] = value;
538
+ added++;
539
+ }
540
+ }
541
+ if (!cfg.model) cfg.model = DEFAULT_GEMINI_PROFILES.model;
542
+
543
+ if (added > 0) {
544
+ writeFileSync(GEMINI_PROFILES_PATH, JSON.stringify(cfg, null, 2) + "\n", "utf8");
545
+ }
546
+
547
+ return { ok: true, created: false, added, count: Object.keys(cfg.profiles).length };
548
+ } catch (e) {
549
+ return { ok: false, message: e.message };
550
+ }
551
+ }
552
+
499
553
  function syncFile(src, dst, label) {
500
554
  const dstDir = dirname(dst);
501
555
  if (!existsSync(dstDir)) mkdirSync(dstDir, { recursive: true });
@@ -869,19 +923,42 @@ function cmdSetup(options = {}) {
869
923
  }
870
924
  }
871
925
 
926
+ // ── 결과 추적 ──
927
+ const summary = [];
928
+
872
929
  const codexProfileResult = ensureCodexProfiles();
873
930
  if (!codexProfileResult.ok) {
874
931
  warn(`Codex profiles 설정 실패: ${codexProfileResult.message}`);
932
+ summary.push({ item: "Codex profiles", status: "⚠️", detail: codexProfileResult.message });
875
933
  } else if (codexProfileResult.added > 0) {
876
934
  ok(`Codex profiles: ${codexProfileResult.added}개 추가됨 (~/.codex/config.toml)`);
935
+ summary.push({ item: "Codex profiles", status: "✅", detail: `${codexProfileResult.added}개 추가됨` });
877
936
  } else {
878
937
  ok("Codex profiles: 이미 준비됨");
938
+ summary.push({ item: "Codex profiles", status: "✅", detail: "이미 준비됨" });
939
+ }
940
+
941
+ // Gemini 프로필
942
+ const geminiResult = ensureGeminiProfiles();
943
+ if (!geminiResult.ok) {
944
+ warn(`Gemini profiles 설정 실패: ${geminiResult.message}`);
945
+ summary.push({ item: "Gemini profiles", status: "⚠️", detail: geminiResult.message });
946
+ } else if (geminiResult.created) {
947
+ ok(`Gemini profiles: ${geminiResult.count}개 생성됨 (~/.gemini/triflux-profiles.json)`);
948
+ summary.push({ item: "Gemini profiles", status: "✅", detail: `${geminiResult.count}개 생성됨` });
949
+ } else if (geminiResult.added > 0) {
950
+ ok(`Gemini profiles: ${geminiResult.added}개 추가됨`);
951
+ summary.push({ item: "Gemini profiles", status: "✅", detail: `${geminiResult.added}개 추가됨 (총 ${geminiResult.count}개)` });
952
+ } else {
953
+ ok(`Gemini profiles: ${geminiResult.count}개 준비됨`);
954
+ summary.push({ item: "Gemini profiles", status: "✅", detail: `${geminiResult.count}개 준비됨` });
879
955
  }
880
956
 
881
957
  // hub MCP 사전 등록 (서버 미실행이어도 설정만 등록 — hub start 시 즉시 사용 가능)
882
958
  if (existsSync(join(PKG_ROOT, "hub", "server.mjs"))) {
883
959
  const defaultHubUrl = `http://127.0.0.1:${process.env.TFX_HUB_PORT || "27888"}/mcp`;
884
960
  autoRegisterMcp(defaultHubUrl);
961
+ summary.push({ item: "Hub MCP", status: "✅", detail: "등록됨" });
885
962
  console.log("");
886
963
  }
887
964
 
@@ -900,6 +977,7 @@ function cmdSetup(options = {}) {
900
977
  const currentCmd = settings.statusLine?.command || "";
901
978
  if (currentCmd.includes("hud-qos-status.mjs")) {
902
979
  ok("statusLine 이미 설정됨");
980
+ summary.push({ item: "HUD statusLine", status: "✅", detail: "이미 설정됨" });
903
981
  } else {
904
982
  const nodePath = process.execPath.replace(/\\/g, "/");
905
983
  const hudForward = hudPath.replace(/\\/g, "/");
@@ -917,6 +995,7 @@ function cmdSetup(options = {}) {
917
995
 
918
996
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
919
997
  ok("statusLine 설정 완료 — 세션 재시작 후 HUD 표시");
998
+ summary.push({ item: "HUD statusLine", status: "✅", detail: "설정 완료" });
920
999
  }
921
1000
  } catch (e) {
922
1001
  throw createCliError(`settings.json 처리 실패: ${e.message}`, {
@@ -928,9 +1007,50 @@ function cmdSetup(options = {}) {
928
1007
  }
929
1008
  } else {
930
1009
  warn("HUD 파일 없음 — 먼저 파일 동기화 필요");
1010
+ summary.push({ item: "HUD statusLine", status: "⚠️", detail: "HUD 파일 없음" });
1011
+ }
1012
+
1013
+ // CLI 존재 확인
1014
+ const cliChecks = [
1015
+ { name: "codex", install: "npm i -g @openai/codex" },
1016
+ { name: "gemini", install: "npm i -g @google/gemini-cli" },
1017
+ ];
1018
+ for (const { name, install } of cliChecks) {
1019
+ if (which(name)) {
1020
+ summary.push({ item: `${name} CLI`, status: "✅", detail: "설치됨" });
1021
+ } else {
1022
+ summary.push({ item: `${name} CLI`, status: "⏭️", detail: `미설치 (${install})` });
1023
+ }
931
1024
  }
932
1025
 
933
- console.log(`\n${DIM}설치 위치: ${CLAUDE_DIR}${RESET}\n`);
1026
+ // Star request (버전 게이팅)
1027
+ const showStar = STAR_PROMPT_VERSIONS.length === 0 || STAR_PROMPT_VERSIONS.includes(PKG.version);
1028
+ if (showStar) {
1029
+ try {
1030
+ execFileSync("gh", ["auth", "status"], { timeout: 5000, stdio: ["pipe", "pipe", "pipe"] });
1031
+ try {
1032
+ execFileSync("gh", ["api", "user/starred/tellang/triflux"], { timeout: 5000, stdio: ["pipe", "pipe", "pipe"] });
1033
+ console.log();
1034
+ ok(`이미 함께하고 계시군요. ${AMBER}⭐${RESET}`);
1035
+ } catch {
1036
+ console.log();
1037
+ info(`${AMBER}⭐${RESET} 하나가 큰 차이를 만듭니다. ${CYAN}https://github.com/tellang/triflux${RESET}`);
1038
+ }
1039
+ } catch {
1040
+ console.log();
1041
+ info(`${AMBER}⭐${RESET} 하나가 큰 차이를 만듭니다. ${CYAN}https://github.com/tellang/triflux${RESET}`);
1042
+ }
1043
+ }
1044
+
1045
+ // ── 결과 요약 테이블 ──
1046
+ console.log(`\n${BOLD}── 설정 요약 ──${RESET}`);
1047
+ const maxItem = Math.max(...summary.map((s) => s.item.length));
1048
+ for (const { item, status, detail } of summary) {
1049
+ console.log(` ${status} ${item.padEnd(maxItem)} ${DIM}${detail}${RESET}`);
1050
+ }
1051
+
1052
+ console.log(`\n${DIM}설치 위치: ${CLAUDE_DIR}${RESET}`);
1053
+ console.log(`${DIM}버전: v${PKG.version}${RESET}\n`);
934
1054
  }
935
1055
 
936
1056
  function addDoctorCheck(report, entry) {
@@ -1849,7 +1969,7 @@ function cmdUpdate() {
1849
1969
  return;
1850
1970
  }
1851
1971
 
1852
- // 3. setup 재실행 (tfx-route.sh, HUD, 스킬 동기화)
1972
+ // 3. setup 재실행 (파일 동기화, 프로파일, HUD, CLI 확인)
1853
1973
  if (updated) {
1854
1974
  console.log("");
1855
1975
  // 업데이트 후 새 버전 읽기
@@ -1865,18 +1985,17 @@ function cmdUpdate() {
1865
1985
  ok(`버전: v${oldVer} (이미 최신)`);
1866
1986
  }
1867
1987
 
1868
- // setup 재실행
1869
- console.log("");
1870
- info("setup 재실행 중...");
1988
+ // setup 재실행 — 개선된 cmdSetup()이 Gemini 프로필, CLI 확인, 요약 테이블 포함
1989
+ console.log(`\n${CYAN}── 설정 동기화 ──${RESET}`);
1871
1990
  cmdSetup();
1872
1991
 
1873
1992
  if (stoppedHubInfo) {
1874
- if (startHubAfterUpdate(stoppedHubInfo)) info("hub 재기동 완료");
1993
+ if (startHubAfterUpdate(stoppedHubInfo)) ok("hub 재기동 완료");
1875
1994
  else warn("hub 재기동 실패 — `tfx hub start`로 수동 시작 필요");
1876
1995
  }
1877
1996
  }
1878
1997
 
1879
- console.log(`${GREEN}${BOLD}업데이트 완료${RESET}\n`);
1998
+ console.log(`${GREEN}${BOLD}업데이트 완료${RESET}\n`);
1880
1999
  }
1881
2000
 
1882
2001
  function cmdList(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "9.0.0",
3
+ "version": "9.2.0",
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": {
package/scripts/setup.mjs CHANGED
@@ -331,6 +331,56 @@ function ensureCodexProfiles() {
331
331
  }
332
332
  }
333
333
 
334
+ const GEMINI_DIR = join(homedir(), ".gemini");
335
+ const GEMINI_PROFILES_PATH = join(GEMINI_DIR, "triflux-profiles.json");
336
+
337
+ const DEFAULT_GEMINI_PROFILES = {
338
+ model: "gemini-3.1-pro-preview",
339
+ profiles: {
340
+ pro31: { model: "gemini-3.1-pro-preview", hint: "3.1 Pro — 플래그십 (1M ctx, 멀티모달)" },
341
+ flash3: { model: "gemini-3-flash-preview", hint: "3.0 Flash — 빠른 응답, 비용 효율" },
342
+ pro25: { model: "gemini-2.5-pro", hint: "2.5 Pro — 안정 (추론 강화)" },
343
+ flash25: { model: "gemini-2.5-flash", hint: "2.5 Flash — 경량 범용" },
344
+ lite25: { model: "gemini-2.5-flash-lite", hint: "2.5 Flash Lite — 최경량" },
345
+ },
346
+ };
347
+
348
+ function ensureGeminiProfiles() {
349
+ try {
350
+ if (!existsSync(GEMINI_DIR)) mkdirSync(GEMINI_DIR, { recursive: true });
351
+
352
+ if (!existsSync(GEMINI_PROFILES_PATH)) {
353
+ writeFileSync(GEMINI_PROFILES_PATH, JSON.stringify(DEFAULT_GEMINI_PROFILES, null, 2) + "\n", "utf8");
354
+ return Object.keys(DEFAULT_GEMINI_PROFILES.profiles).length;
355
+ }
356
+
357
+ let cfg;
358
+ try {
359
+ cfg = JSON.parse(readFileSync(GEMINI_PROFILES_PATH, "utf8"));
360
+ } catch {
361
+ writeFileSync(GEMINI_PROFILES_PATH, JSON.stringify(DEFAULT_GEMINI_PROFILES, null, 2) + "\n", "utf8");
362
+ return Object.keys(DEFAULT_GEMINI_PROFILES.profiles).length;
363
+ }
364
+
365
+ if (!cfg.profiles) cfg.profiles = {};
366
+ let added = 0;
367
+ for (const [name, value] of Object.entries(DEFAULT_GEMINI_PROFILES.profiles)) {
368
+ if (!cfg.profiles[name]) {
369
+ cfg.profiles[name] = value;
370
+ added++;
371
+ }
372
+ }
373
+ if (!cfg.model) cfg.model = DEFAULT_GEMINI_PROFILES.model;
374
+
375
+ if (added > 0) {
376
+ writeFileSync(GEMINI_PROFILES_PATH, JSON.stringify(cfg, null, 2) + "\n", "utf8");
377
+ }
378
+ return added;
379
+ } catch {
380
+ return 0;
381
+ }
382
+ }
383
+
334
384
  export { replaceProfileSection, hasProfileSection, detectDevMode, SYNC_MAP, BREADCRUMB_PATH, PLUGIN_ROOT, CLAUDE_DIR, SKILL_ALIASES };
335
385
 
336
386
  async function main() {
@@ -813,6 +863,13 @@ if (codexProfilesAdded > 0) {
813
863
  synced++;
814
864
  }
815
865
 
866
+ // ── Gemini 프로필 자동 보정 ──
867
+
868
+ const geminiProfilesAdded = ensureGeminiProfiles();
869
+ if (geminiProfilesAdded > 0) {
870
+ synced++;
871
+ }
872
+
816
873
  // ── MCP 인벤토리 백그라운드 갱신 ──
817
874
 
818
875
  const mcpCheck = join(PLUGIN_ROOT, "scripts", "mcp-check.mjs");
@@ -0,0 +1,122 @@
1
+ ---
2
+ name: star-prompt
3
+ description: >-
4
+ CLI 프로젝트의 setup/postinstall 흐름에 GitHub 스타 요청 프롬프트를 추가한다.
5
+ gh CLI 인증 확인 → 이미 스타 여부 감지 → 인터랙티브 confirm → gh API로 자동 스타.
6
+ Apple 스타일 UX 카피 포함. 'star prompt', '스타 요청', '리포 스타', 'star request',
7
+ '깃헙 스타 넣어줘', 'star 눌러달라고', '응원 요청' 같은 요청에 사용한다.
8
+ ---
9
+
10
+ # tfx-star-prompt — GitHub Star Request Prompt
11
+
12
+ CLI 도구의 setup 완료 시점에 GitHub 리포 스타를 요청하는 프롬프트를 추가한다.
13
+ 사용자 경험을 해치지 않으면서, 이미 스타한 사용자에겐 감사를 표하고, 아직 안 한 사용자에겐 부담 없이 한 번 물어본다.
14
+
15
+ ## 동작 흐름
16
+
17
+ ```
18
+ gh auth status ─── 실패 → URL만 표시 (비인터랙티브 폴백)
19
+
20
+ ✓ 인증됨
21
+
22
+ gh api user/starred/{owner}/{repo} ─── 성공 → "이미 함께하고 계시군요. ⭐"
23
+
24
+ ✗ 미스타
25
+
26
+ confirm("⭐ 하나가 큰 차이를 만듭니다.") ─── N → URL 조용히 표시
27
+
28
+ Y
29
+
30
+ gh api -X PUT /user/starred/{owner}/{repo} → "함께해 주셔서 감사합니다. ⭐"
31
+
32
+ 실패 → URL 폴백
33
+ ```
34
+
35
+ ## 구현 패턴
36
+
37
+ ### 인터랙티브 (TUI / readline confirm)
38
+
39
+ setup 위저드 완료 후 호출. `confirm()` 으로 Y/n 입력 받고 `gh api`로 자동 스타.
40
+
41
+ ```javascript
42
+ async function starRequest() {
43
+ let ghOk = false;
44
+ try {
45
+ execFileSync("gh", ["auth", "status"], {
46
+ timeout: 5000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"],
47
+ });
48
+ ghOk = true;
49
+ } catch {}
50
+
51
+ if (!ghOk) {
52
+ // gh 미설치/미인증 — URL만 표시
53
+ info(`⭐ 하나가 큰 차이를 만듭니다. https://github.com/{owner}/{repo}`);
54
+ return;
55
+ }
56
+
57
+ let alreadyStarred = false;
58
+ try {
59
+ execFileSync("gh", ["api", "user/starred/{owner}/{repo}"], {
60
+ timeout: 5000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"],
61
+ });
62
+ alreadyStarred = true;
63
+ } catch {}
64
+
65
+ if (alreadyStarred) {
66
+ ok(`이미 함께하고 계시군요. ⭐`);
67
+ return;
68
+ }
69
+
70
+ if (await confirm(`⭐ 하나가 큰 차이를 만듭니다.`, true)) {
71
+ try {
72
+ execFileSync("gh", ["api", "-X", "PUT", "/user/starred/{owner}/{repo}"], {
73
+ timeout: 5000, stdio: ["pipe", "pipe", "pipe"],
74
+ });
75
+ ok(`함께해 주셔서 감사합니다. ⭐`);
76
+ } catch {
77
+ info(`https://github.com/{owner}/{repo}`);
78
+ }
79
+ } else {
80
+ // 거절 시 URL만 조용히
81
+ console.log(` https://github.com/{owner}/{repo}`);
82
+ }
83
+ }
84
+ ```
85
+
86
+ ### 비인터랙티브 (postinstall / CLI banner)
87
+
88
+ confirm 불가한 환경. 이미 스타 여부만 감지하고 메시지 분기.
89
+
90
+ ```javascript
91
+ try {
92
+ execFileSync("gh", ["auth", "status"], { timeout: 5000, stdio: ["pipe","pipe","pipe"] });
93
+ try {
94
+ execFileSync("gh", ["api", "user/starred/{owner}/{repo}"], { timeout: 5000, stdio: ["pipe","pipe","pipe"] });
95
+ ok(`이미 함께하고 계시군요. ⭐`);
96
+ } catch {
97
+ info(`⭐ 하나가 큰 차이를 만듭니다. https://github.com/{owner}/{repo}`);
98
+ }
99
+ } catch {
100
+ info(`⭐ 하나가 큰 차이를 만듭니다. https://github.com/{owner}/{repo}`);
101
+ }
102
+ ```
103
+
104
+ ## 적용 시 규칙
105
+
106
+ 1. `{owner}/{repo}`를 대상 리포로 치환한다
107
+ 2. 프로젝트의 기존 ANSI 컬러 상수(AMBER, CYAN, RESET 등)를 사용한다
108
+ 3. setup 완료 직후, 최종 요약 다음에 호출한다 — 핵심 설정 흐름을 방해하지 않는다
109
+ 4. 모든 gh 호출은 `timeout: 5000`, `stdio: ["pipe","pipe","pipe"]`로 감싸서 실패해도 setup을 블로킹하지 않는다
110
+ 5. 거절 시 죄책감을 주지 않는다 — URL만 조용히 남긴다
111
+
112
+ ## UX 카피 톤
113
+
114
+ Apple 스타일: 짧고, 자신감 있고, 부담 없이.
115
+
116
+ | 상황 | 멘트 |
117
+ |------|------|
118
+ | 이미 스타 | `이미 함께하고 계시군요. ⭐` |
119
+ | 요청 | `⭐ 하나가 큰 차이를 만듭니다.` |
120
+ | 수락 후 | `함께해 주셔서 감사합니다. ⭐` |
121
+ | 거절 | URL만 |
122
+ | gh 없음 | `⭐ 하나가 큰 차이를 만듭니다.` + URL |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tfx-codex-swarm
3
- description: OMX 스킬을 활용하는 Codex 다중 세션 스폰 오케스트레이터. PRD/태스크 파일을 스캔하여 각각 독립 git worktree + psmux 세션���로 Codex를 full-auto 실행한다. 'codex swarm', 'codex 다중', '코덱스 스웜', '코덱스 다중 실행', 'PRD 일괄 실행', 'codex spawn', '코덱스 스폰', '다중 코덱스', 'swarm codex', 'omx swarm' 같은 요청에 반드시 사용. PRD가 여러 개이거나 병렬 Codex 실행이 필요한 모든 상황에 적극 활용.
3
+ description: OMX 스킬을 활용하는 Codex 다중 세션 스폰 오케스트레이터. PRD/태스크 파일을 스캔하여 각각 독립 git worktree + psmux 세션���로 Codex를 full-auto 실행한다. 'codex swarm', 'codex 다중', '코덱스 스웜', '코덱스 다중 실행', 'PRD 일괄 실행', 'codex spawn', '코덱스 스폰', '다중 코덱스', 'swarm codex', 'omx swarm', '새 창에서 진행', '새 창에서 prd', 'prd 부터', 'prd 실행', 'prd 돌려', '병렬로 돌려', 'worktree로 실행' 같은 요청에 반드시 사용. PRD가 여러 개이거나 병렬 Codex 실행이 필요한 모든 상황에 적극 활용.
4
4
  ---
5
5
 
6
6
  # tfx-codex-swarm — Codex 다중 세션 스폰 오케스트레이터
@@ -10,10 +10,11 @@ description: OMX 스킬을 활용하는 Codex 다중 세션 스폰 오케스트
10
10
 
11
11
  ## 전제 조건
12
12
 
13
- - `codex` CLI 설치됨
13
+ - **`tfx-psmux-rules` 스킬 필수** — psmux 명령/런처 생성 시 이 스킬의 규칙을 반드시 준수
14
+ - `codex` CLI 설치됨 (0.117.0+)
14
15
  - `psmux` 설치됨 (세션 관리)
15
16
  - `git` (worktree 생성)
16
- - Windows Terminal (`wt.exe` 기반 attach)
17
+ - Windows Terminal (`wt.exe` 패인 기반 attach)
17
18
  - MCP 싱글톤 데몬 (`supergateway` + `mcp-remote`) — 선택적이나 스웜 시 강력 권장
18
19
 
19
20
  ## 설정
@@ -176,18 +177,25 @@ PRD 파일을 읽고 아래 시그널에서 규모를 판단한다:
176
177
  |-------------|-----|-----|-----|-----|
177
178
  | **구현** | `codex53_xhigh` | `codex53_high` | `codex53_med` | `codex53_low` |
178
179
  | **조사** | `gpt54_high` | `gpt54_high` | `gpt54_low` | `mini54_med` |
179
- | **리팩터링** | `codex53_xhigh` | `codex53_high` | `codex53_med` | `spark53_med` |
180
- | **린트/포맷** | — | — | `spark53_med` | `spark53_low` |
180
+ | **리팩터링** | `codex53_xhigh` | `codex53_high` | `codex53_med` | `codex53_low` |
181
+ | **린트/포맷** | — | — | `codex53_low` | `codex53_low` |
181
182
 
182
- 프로파일은 `~/.codex/config.toml`의 v9 체계(`{model}{ver}_{effort}`)를 `-p` 플래그로 직접 참조한다.
183
- `-c` 하드코딩은 사용하지 않는다. (레거시 `fast/normal/high` 프로파일도 사용하지 않는다.)
183
+ > **NOTE**: `spark53_*` 프로파일은 Pro 구독 전용. 비-Pro 환경에서는 `codex53_low`로 폴백한다.
184
+
185
+ 프로파일 이름(`codex53_high` 등)은 `~/.codex/config.toml`에 정의된 프로파일이다.
186
+ **모델·effort·실행모드는 인자로 하드코딩하지 않고 프로파일로 관리한다.**
187
+ (→ tfx-psmux-rules RULE 4)
184
188
 
185
189
  ```bash
186
- # 예시: -p 플래그로 프로파일 지정
187
- codex -p codex53_high --dangerously-bypass-approvals-and-sandbox "prompt"
188
- codex -p gpt54_high --dangerously-bypass-approvals-and-sandbox "prompt"
190
+ # 프로파일이 config.toml에 정의되어 있으면 깔끔하게 호출
191
+ codex < prompt.md
192
+
193
+ # 프로파일 관리: tfx-profile 스킬 또는 config.toml 직접 편집
189
194
  ```
190
195
 
196
+ > **config.toml 중복 금지**: 이미 설정된 값을 CLI 플래그로 다시 지정하면 에러.
197
+ > 런처 생성 전 config.toml 확인 필수.
198
+
191
199
  #### 4-3. 라우팅 결과 표시
192
200
 
193
201
  프로파일 결정 후 테이블로 표시한다:
@@ -221,7 +229,7 @@ options:
221
229
 
222
230
  | 설정 | 기본값 | 설명 |
223
231
  |------|--------|------|
224
- | 실행 모드 | `--dangerously-bypass-approvals-and-sandbox` | YOLO (승인+샌드박스 완전 해제). `--skip-git-repo-check`는 `codex exec` 전용이므로 대화식에서 사용 금지 |
232
+ | 실행 모드 | `--full-auto` (config.toml 미설정 시만) | config.toml에 `approval_mode`/`sandbox` 이미 있으면 **생략 필수** (중복 에러). `--skip-git-repo-check`는 `codex exec` 전용 |
225
233
  | worktree | 활성화 | 세션당 독립 worktree |
226
234
  | psmux | 활성화 | 세션 관리 |
227
235
 
@@ -287,41 +295,94 @@ cp {PRD_PATH} .codex-swarm/wt-issue-{N}/{PRD_PATH}
287
295
 
288
296
  각 태스크에 대해 psmux 세션을 생성하고 Codex를 실행한다:
289
297
 
298
+ > **CRITICAL — psmux 셸 = PowerShell**
299
+ > psmux 세션의 기본 셸은 **PowerShell**이다. `cd '/c/...'`, `$(cat ...)`, `&&` 등
300
+ > bash 문법을 `send-keys`로 직접 전달하면 경로 오류 + 인자 파싱 실패가 발생한다.
301
+ > **반드시 `.sh` 런처 파일을 생성하고, PowerShell 구문으로 bash.exe 전체 경로를 호출해야 한다.**
302
+
303
+ **실행 방식 2가지 (택 1):**
304
+
305
+ **A) .sh 런처 + send-keys (권장)**
290
306
  ```bash
291
- # 세션 생성 (-s: 세션명, -d: detached 백그라운드)
292
- # psmux 기본 셸이 PowerShell이므로, bash 런처 스크립트를 PowerShell에서 호출
293
307
  psmux new-session -s "codex-swarm-{id}" -d
294
308
 
295
- # bash 런처를 PowerShell 구문으로 실행 (경로는 Windows 형식)
309
+ # PowerShell 구문으로 bash.exe를 호출 — 경로는 반드시 Windows 형식
296
310
  BASH_WIN='C:\\Program Files\\Git\\bin\\bash.exe'
297
311
  LAUNCH_DIR='C:\\path\\to\\.codex-swarm'
298
312
  psmux send-keys -t "codex-swarm-{id}" \
299
313
  "& '$BASH_WIN' '$LAUNCH_DIR\\launch-{id}.sh'" Enter
314
+ ```
300
315
 
301
- # launch-{id}.sh 내용:
302
- # #!/bin/bash
303
- # cd /c/path/.codex-swarm/wt-issue-{N} || exit 1
304
- # prompt=$(cat /c/path/.codex-swarm/prompts/prompt-{id}.md)
305
- # exec codex -p {PROFILE} --dangerously-bypass-approvals-and-sandbox "$prompt"
306
- #
307
- # {PROFILE}은 Step 4 라우팅 결과: codex53_high, gpt54_high 등 (v9 체계)
308
- # --dangerously-bypass-approvals-and-sandbox: 진짜 YOLO (승인+샌드박스 완전 해제)
309
- # --skip-git-repo-check: codex exec 전용이므로 대화식 모드에서 사용 불가
316
+ launch-{id}.sh:
317
+ ```bash
318
+ #!/bin/bash
319
+ cd /c/path/.codex-swarm/wt-issue-{N} || exit 1
320
+ # stdin으로 프롬프트 전달 (-- 접두사 텍스트 파싱 회피)
321
+ exec codex < /c/path/.codex-swarm/prompts/prompt-{id}.md
322
+ # config.toml에 model/approval_mode 미설정 시만 플래그 추가:
323
+ # exec codex -c 'model="gpt-5.3-codex"' -c 'model_reasoning_effort="high"' --full-auto < prompt.md
310
324
  ```
311
325
 
326
+ **B) .ps1 런처 + send-keys**
327
+ ```bash
328
+ psmux new-session -s "codex-swarm-{id}" -d
329
+ psmux send-keys -t "codex-swarm-{id}" \
330
+ "& '.\\launch-{id}.ps1'" Enter
331
+ ```
332
+
333
+ launch-{id}.ps1:
334
+ ```powershell
335
+ Set-Location 'C:\path\.codex-swarm\wt-issue-{N}'
336
+ # stdin 파이프로 전달 (& ; | -- 등 특수문자 안전)
337
+ Get-Content 'C:\path\.codex-swarm\prompts\prompt-{id}.md' -Raw | codex
338
+ # config.toml에 model 미설정 시만:
339
+ # Get-Content 'prompt.md' -Raw | codex -c 'model="gpt-5.3-codex"' -c 'model_reasoning_effort="high"'
340
+ ```
341
+
342
+ > **금지 패턴** (절대 사용하지 말 것):
343
+ > ```bash
344
+ > # WRONG — bash 문법을 PowerShell 세션에 직접 전달
345
+ > psmux send-keys -t "codex-swarm-{id}" \
346
+ > "cd '/c/path/...' && codex -p profile \"$(cat prompt.md)\"" Enter
347
+ > ```
348
+
349
+ {PROFILE}은 Step 4 라우팅 결과 → `-c` 쌍으로 변환 (4-2 매핑 테이블 참조).
350
+ 실행 모드/모델 설정은 `~/.codex/config.toml` 우선. CLI 플래그는 미설정 항목만 추가.
351
+
312
352
  ### Step 8: WT attach
313
353
 
314
354
  > WT `triflux` 프로파일 사용 필수 (`commandline: "psmux"`, One Half Dark, acrylic).
315
- > 기본은 **split-pane 직접 attach**. 4개 이하 2x2 그리드, 5개 이상은 사용자 확인.
355
+ > **새 탭(nt) 금지** split + dashboard가 기본.
356
+
357
+ **WT 레이아웃은 반드시 AskUserQuestion으로 먼저 확인한다:**
358
+
359
+ ```
360
+ question: "WT 레이아웃을 선택하세요"
361
+ header: "WT 배치"
362
+ options:
363
+ - label: "새 창에서 스플릿"
364
+ description: "새 WT 윈도우를 열고 세션을 split-pane으로 배치"
365
+ - label: "현재 창에서 스플릿"
366
+ description: "현재 WT 윈도우(-w 0)에 split-pane 추가"
367
+ - label: "dashboard 모드"
368
+ description: "모니터링 전용 단일 패인 (10초 폴링)"
369
+ - label: "attach 안 함"
370
+ description: "psmux 세션만 생성, WT attach 생략"
371
+ ```
372
+
373
+ 선택에 따른 wt.exe 명령:
316
374
 
317
375
  ```bash
376
+ # [새 창에서 스플릿] — wt -w new
377
+ # [현재 창에서 스플릿] — wt -w 0
378
+
318
379
  # 2개: 상하 분할
319
- wt.exe -w 0 \
380
+ wt.exe -w {WINDOW} \
320
381
  sp -H -p triflux --title "{t1}" psmux attach-session -t {id1} \; \
321
382
  sp -V -p triflux --title "{t2}" psmux attach-session -t {id2}
322
383
 
323
384
  # 4개: 2x2 그리드
324
- wt.exe -w 0 \
385
+ wt.exe -w {WINDOW} \
325
386
  sp -H -p triflux --title "{t1}" psmux attach-session -t {id1} \; \
326
387
  sp -V -p triflux --title "{t2}" psmux attach-session -t {id2} \; \
327
388
  move-focus up \; \
@@ -330,7 +391,7 @@ wt.exe -w 0 \
330
391
  sp -V -p triflux --title "{t4}" psmux attach-session -t {id4}
331
392
  ```
332
393
 
333
- 5개 이상이면 AskUserQuestion으로 확인 후 dashboard 모드 제안:
394
+ 5개 이상이면 dashboard 모드를 추천:
334
395
  ```bash
335
396
  # dashboard 모드 (모니터링 전용)
336
397
  wt.exe -w 0 -p triflux --title "swarm-dashboard" bash -c '
@@ -481,13 +542,26 @@ fi
481
542
  ## 정리
482
543
 
483
544
  전체 스웜 종료 시:
545
+
546
+ > **WT 프리징 방지**: `kill-session` 전에 반드시 각 세션에 `exit`을 보내
547
+ > 프로세스를 정상 종료시킨다. WT 패인이 attach 중인 상태에서 세션을
548
+ > 강제 kill하면 WT가 응답 없음 상태로 전환될 수 있다.
549
+
484
550
  ```bash
485
- # 세션 종료
551
+ # 1) graceful exit — 각 세션에 exit 전송 (WT 패인 자연 종료 유도)
552
+ for s in $(psmux list-sessions -F '#{session_name}' 2>/dev/null | grep codex-swarm); do
553
+ psmux send-keys -t "$s" "exit" Enter 2>/dev/null || true
554
+ done
555
+
556
+ # 2) 프로세스 종료 대기 (WT 패인이 닫힐 시간 확보)
557
+ sleep 2
558
+
559
+ # 3) 잔여 세션 강제 종료 (exit이 먹히지 않은 경우)
486
560
  for s in $(psmux list-sessions -F '#{session_name}' 2>/dev/null | grep codex-swarm); do
487
- psmux kill-session -t "$s"
561
+ psmux kill-session -t "$s" 2>/dev/null || true
488
562
  done
489
563
 
490
- # worktree 정리 (머지 완료된 것만)
564
+ # 4) worktree 정리 (머지 완료된 것만)
491
565
  git worktree prune
492
566
  rm -rf .codex-swarm/
493
567
  ```
@@ -0,0 +1,208 @@
1
+ ---
2
+ name: tfx-psmux-rules
3
+ description: >
4
+ psmux + Codex CLI 명령 생성 시 반드시 적용되는 강제 규칙. PowerShell/bash 구분,
5
+ 경로 형식, 인자 이스케이프, WT 정리, 프로파일 지정 방식 등을 검증한다.
6
+ 이 스킬은 psmux, send-keys, codex exec, codex spawn, 세션 생성, worktree 실행,
7
+ launch 스크립트 생성, WT attach, 패널 스플릿, 스웜 정리 시 자동 트리거된다.
8
+ 다른 스킬(tfx-codex-swarm, tfx-multi, tfx-remote-spawn 등)이 psmux 명령을
9
+ 생성할 때 이 스킬의 규칙을 위반하면 생성을 중단하고 수정해야 한다.
10
+ triggers:
11
+ - tfx-psmux-rules
12
+ - psmux-rules
13
+ ---
14
+
15
+ # tfx-psmux-rules — psmux + Codex CLI 강제 규칙
16
+
17
+ > **이 스킬은 참고 문서가 아니다. 강제 규칙이다.**
18
+ > psmux 명령, launch 스크립트, Codex CLI 호출을 생성하는 모든 스킬은
19
+ > 아래 규칙을 **반드시** 준수해야 한다. 위반 시 생성을 중단하고 수정한다.
20
+
21
+ ## 적용 시점
22
+
23
+ 다음 행위 중 하나라도 수행할 때 이 규칙이 자동 적용된다:
24
+ - `psmux send-keys` 명령 생성
25
+ - `launch-*.sh` 또는 `launch-*.ps1` 스크립트 생성
26
+ - `codex` CLI 호출 인자 조합
27
+ - `wt.exe` 탭/패인 명령 생성
28
+ - 스웜 세션 정리
29
+
30
+ ---
31
+
32
+ ## RULE 1: psmux 기본 셸 = PowerShell
33
+
34
+ psmux 세션의 기본 셸은 **PowerShell**이다.
35
+
36
+ ### MUST NOT (금지)
37
+
38
+ ```bash
39
+ # WRONG — bash 문법을 PowerShell 세션에 직접 전달
40
+ psmux send-keys -t session "cd '/c/Users/...' && codex ..." Enter
41
+ psmux send-keys -t session "prompt=\$(cat file.md)" Enter
42
+ psmux send-keys -t session "export FOO=bar" Enter
43
+ ```
44
+
45
+ ### MUST (필수)
46
+
47
+ ```bash
48
+ # CORRECT — PowerShell 구문으로 bash.exe 전체 경로 호출
49
+ BASH_WIN='C:\\Program Files\\Git\\bin\\bash.exe'
50
+ psmux send-keys -t session "& '$BASH_WIN' './launch.sh'" Enter
51
+
52
+ # CORRECT — PowerShell 네이티브 명령 사용
53
+ psmux send-keys -t session "Set-Location 'C:\\path'" Enter
54
+ psmux send-keys -t session "\$p = Get-Content 'file.md' -Raw" Enter
55
+ ```
56
+
57
+ ### 금지 패턴 체크리스트
58
+
59
+ | 패턴 | 문제 | 대체 |
60
+ |------|------|------|
61
+ | `cd '/c/...'` | PS가 `/c/`를 상대경로로 해석 → `C:\c\...` | `Set-Location 'C:\...'` |
62
+ | `$(cat file)` | bash 명령 치환, PS에서 `Get-Content` 호출됨 | `$p = Get-Content file -Raw` |
63
+ | `&&` | PS7에서 작동하지만 앞 명령 실패 시 의미 다름 | `;` 또는 별도 send-keys |
64
+ | `export VAR=val` | bash 전용 | `$env:VAR = 'val'` |
65
+ | `grep`, `awk`, `sed` | bash 유틸리티 | PS cmdlet 또는 bash.exe 경유 |
66
+
67
+ ---
68
+
69
+ ## RULE 2: 경로는 Windows 형식
70
+
71
+ psmux send-keys로 전달하는 경로는 반드시 **Windows 형식**이다.
72
+
73
+ ```
74
+ WRONG: /c/Users/SSAFY/Desktop/Projects/...
75
+ RIGHT: C:\Users\SSAFY\Desktop\Projects\...
76
+ ```
77
+
78
+ `.sh` 런처 내부에서만 Unix 경로(`/c/...`) 사용 가능.
79
+
80
+ ---
81
+
82
+ ## RULE 3: 프롬프트 인자 인용 필수
83
+
84
+ PRD/프롬프트 내용을 CLI 인자로 전달할 때 **반드시 인용**한다.
85
+
86
+ ### PowerShell (.ps1)
87
+
88
+ ```powershell
89
+ $p = (Get-Content 'prompt.md' -Raw) -replace "`r`n"," " -replace "`n"," "
90
+
91
+ # MUST — 인용 필수
92
+ codex -c 'model="gpt-5.3-codex"' "$p"
93
+
94
+ # MUST NOT — 미인용 시 & ; | 등이 PS 연산자로 해석됨
95
+ codex -c 'model="gpt-5.3-codex"' $p
96
+ ```
97
+
98
+ ### Bash (.sh)
99
+
100
+ ```bash
101
+ prompt=$(cat prompt.md)
102
+
103
+ # MUST — 더블쿼트 필수
104
+ exec codex "$prompt"
105
+
106
+ # MUST NOT — 워드 스플리팅 + 글로빙 발생
107
+ exec codex $prompt
108
+ ```
109
+
110
+ ---
111
+
112
+ ## RULE 4: 프로파일 사용, 인자 하드코딩 금지
113
+
114
+ Codex든 Gemini든 **모델·effort·실행모드는 프로파일(config)로 관리**한다.
115
+ CLI 인자로 하드코딩하지 않는다.
116
+
117
+ ### 4-1. 프로파일 우선
118
+
119
+ ```bash
120
+ # CORRECT — 프로파일에 model/effort/approval_mode 모두 정의해두고 호출
121
+ codex < prompt.md
122
+ codex --full-auto < prompt.md # config.toml에 approval_mode 미설정 시만
123
+
124
+ # WRONG — 인자로 모델·effort 하드코딩
125
+ codex -c 'model="gpt-5.3-codex"' -c 'model_reasoning_effort="high"' "prompt"
126
+ ```
127
+
128
+ 프로파일 관리는 `tfx-profile` 스킬 또는 `~/.codex/config.toml` 직접 편집.
129
+
130
+ ### 4-2. config.toml 중복 플래그 금지
131
+
132
+ config.toml에 이미 설정된 값을 CLI 플래그로 다시 지정하면 **에러**:
133
+ ```
134
+ error: the argument '--dangerously-bypass-approvals-and-sandbox' cannot be used multiple times
135
+ ```
136
+
137
+ **규칙**: 런처 생성 전 config.toml을 확인하고, 이미 있는 항목은 CLI에서 생략.
138
+
139
+ ### 4-3. 프롬프트는 stdin으로 전달
140
+
141
+ 프롬프트를 CLI 인자로 넘기면 `--` 접두사 텍스트가 플래그로 파싱되는 문제 발생.
142
+ **항상 stdin(파이프 또는 리다이렉션)으로 전달한다.**
143
+
144
+ ```bash
145
+ # bash 런처
146
+ exec codex < /c/path/prompts/prompt.md
147
+ ```
148
+
149
+ ```powershell
150
+ # PS1 런처
151
+ Get-Content 'C:\path\prompts\prompt.md' -Raw | codex
152
+ ```
153
+
154
+ ---
155
+
156
+ ## RULE 5: WT 패인 정리 (프리징 방지)
157
+
158
+ WT 패인이 psmux 세션에 attach된 상태에서 `kill-session`하면 WT가 프리징된다.
159
+
160
+ ### MUST (3단계 정리)
161
+
162
+ ```bash
163
+ # 1) graceful exit
164
+ for s in $(psmux list-sessions -F '#{session_name}' 2>/dev/null | grep codex-swarm); do
165
+ psmux send-keys -t "$s" "exit" Enter 2>/dev/null || true
166
+ done
167
+
168
+ # 2) WT 패인 종료 대기
169
+ sleep 2
170
+
171
+ # 3) 잔여 세션 강제 종료
172
+ for s in $(psmux list-sessions -F '#{session_name}' 2>/dev/null | grep codex-swarm); do
173
+ psmux kill-session -t "$s" 2>/dev/null || true
174
+ done
175
+ ```
176
+
177
+ ### MUST NOT
178
+
179
+ ```bash
180
+ # WRONG — WT 프리징 발생
181
+ for s in $(psmux list-sessions -F '#{session_name}' 2>/dev/null | grep codex-swarm); do
182
+ psmux kill-session -t "$s"
183
+ done
184
+ ```
185
+
186
+ ---
187
+
188
+ ## RULE 6: spark53 프로파일은 Pro 전용
189
+
190
+ `spark53_med`, `spark53_low` 등 spark 모델 프로파일은 **Codex Pro 구독 전용**이다.
191
+ 비-Pro 환경에서는 `codex53_low`로 폴백한다.
192
+
193
+ ---
194
+
195
+ ## RULE 7: WT 레이아웃 선택 필수
196
+
197
+ WT에 패인을 배치하기 전에 **반드시** 사용자에게 레이아웃을 확인한다.
198
+ 새 탭(`nt`)은 금지 — split + dashboard가 기본.
199
+
200
+ 선택지: 새 창에서 스플릿 / 현재 창에서 스플릿 / dashboard / attach 안 함
201
+
202
+ ---
203
+
204
+ ## 위반 감지 시 행동
205
+
206
+ 1. 생성한 명령/스크립트가 위 규칙을 위반하면 **즉시 수정**한다
207
+ 2. 수정 불가능하면 **생성을 중단**하고 사용자에게 알린다
208
+ 3. 다른 스킬이 이 규칙을 무시하고 명령을 생성하면 **경고를 출력**한다
package/tui/setup.mjs CHANGED
@@ -326,6 +326,56 @@ function showSummary(results) {
326
326
  }
327
327
  }
328
328
 
329
+ // ── Star Request ──
330
+
331
+ async function starRequest() {
332
+ let ghOk = false;
333
+ try {
334
+ execFileSync("gh", ["auth", "status"], {
335
+ timeout: 5000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"],
336
+ });
337
+ ghOk = true;
338
+ } catch {}
339
+
340
+ if (!ghOk) {
341
+ console.log();
342
+ info(`${AMBER}⭐${RESET} 하나가 큰 차이를 만듭니다. ${CYAN}https://github.com/tellang/triflux${RESET}`);
343
+ console.log();
344
+ return;
345
+ }
346
+
347
+ // gh 인증됨 — 스타 여부 확인
348
+ let alreadyStarred = false;
349
+ try {
350
+ execFileSync("gh", ["api", "user/starred/tellang/triflux"], {
351
+ timeout: 5000, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"],
352
+ });
353
+ alreadyStarred = true;
354
+ } catch {}
355
+
356
+ console.log();
357
+
358
+ if (alreadyStarred) {
359
+ ok(`이미 함께하고 계시군요. ${AMBER}⭐${RESET}`);
360
+ console.log();
361
+ return;
362
+ }
363
+
364
+ if (await confirm(`${AMBER}⭐${RESET} 하나가 큰 차이를 만듭니다.`, true)) {
365
+ try {
366
+ execFileSync("gh", ["api", "-X", "PUT", "/user/starred/tellang/triflux"], {
367
+ timeout: 5000, stdio: ["pipe", "pipe", "pipe"],
368
+ });
369
+ ok(`함께해 주셔서 감사합니다. ${AMBER}⭐${RESET}`);
370
+ } catch {
371
+ info(`${CYAN}https://github.com/tellang/triflux${RESET}`);
372
+ }
373
+ } else {
374
+ console.log(` ${DIM}${CYAN}https://github.com/tellang/triflux${RESET}`);
375
+ }
376
+ console.log();
377
+ }
378
+
329
379
  // ── Main Menu ──
330
380
 
331
381
  const MENU = [
@@ -357,6 +407,7 @@ async function main() {
357
407
  case 0: {
358
408
  const results = await runWizard();
359
409
  showSummary(results);
410
+ await starRequest();
360
411
  break;
361
412
  }
362
413