triflux 8.6.0 → 8.9.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 +46 -7
- package/README.md +46 -7
- package/hub/team/ansi.mjs +134 -11
- package/hub/team/tui.mjs +288 -53
- package/package.json +1 -1
- package/skills/tfx-consensus/SKILL.md +138 -114
- package/skills/tfx-debate/SKILL.md +96 -57
- package/skills/tfx-deep-analysis/SKILL.md +171 -191
- package/skills/tfx-deep-plan/SKILL.md +181 -73
- package/skills/tfx-deep-qa/SKILL.md +58 -58
- package/skills/tfx-deep-research/SKILL.md +79 -80
- package/skills/tfx-deep-review/SKILL.md +122 -96
- package/skills/tfx-fullcycle/SKILL.md +117 -105
- package/skills/tfx-panel/SKILL.md +66 -69
- package/skills/tfx-persist/SKILL.md +149 -76
- package/skills/tfx-prune/SKILL.md +72 -75
- package/skills/tfx-remote-setup/SKILL.md +530 -0
- package/skills/tfx-remote-spawn/SKILL.md +259 -0
- package/skills/remote-spawn/SKILL.md +0 -205
- /package/skills/{remote-spawn → tfx-remote-spawn}/references/hosts.json +0 -0
package/README.ko.md
CHANGED
|
@@ -17,16 +17,11 @@
|
|
|
17
17
|
<a href="https://www.npmjs.com/package/triflux"><img src="https://img.shields.io/npm/v/triflux?style=flat-square&color=FFAF00&label=npm" alt="npm version"></a>
|
|
18
18
|
<a href="https://www.npmjs.com/package/triflux"><img src="https://img.shields.io/npm/dm/triflux?style=flat-square&color=F5C242" alt="npm downloads"></a>
|
|
19
19
|
<a href="https://github.com/tellang/triflux/stargazers"><img src="https://img.shields.io/github/stars/tellang/triflux?style=flat-square&color=FFAF00" alt="GitHub stars"></a>
|
|
20
|
-
<a href="https://github.com/tellang/triflux/actions"><img src="https://img.shields.io/github/actions/workflow/status/tellang/triflux/ci.yml?style=flat-square&label=CI" alt="CI"></a>
|
|
21
20
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-374151?style=flat-square" alt="License: MIT"></a>
|
|
22
21
|
</p>
|
|
23
22
|
|
|
24
23
|
<p align="center">
|
|
25
|
-
<
|
|
26
|
-
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/demo-dark.gif">
|
|
27
|
-
<source media="(prefers-color-scheme: light)" srcset="docs/assets/demo-light.gif">
|
|
28
|
-
<img alt="triflux 데모" src="docs/assets/demo-dark.gif" width="680">
|
|
29
|
-
</picture>
|
|
24
|
+
<img alt="triflux 데모" src="docs/assets/demo-multi.gif" width="680">
|
|
30
25
|
</p>
|
|
31
26
|
|
|
32
27
|
<p align="center">
|
|
@@ -40,6 +35,49 @@
|
|
|
40
35
|
|
|
41
36
|
---
|
|
42
37
|
|
|
38
|
+
## 빠른 시작
|
|
39
|
+
|
|
40
|
+
### 1. 설치
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g triflux
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. 설정
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
tfx setup
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. 사용법
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Light — 단일 모델로 빠르게 실행
|
|
56
|
+
/tfx-research "React 19 Server Actions best practices"
|
|
57
|
+
/tfx-review
|
|
58
|
+
/tfx-plan "add JWT auth middleware"
|
|
59
|
+
|
|
60
|
+
# Deep — 중요한 작업에 3자 합의 적용
|
|
61
|
+
/tfx-deep-research "microservice architecture comparison 2026"
|
|
62
|
+
/tfx-deep-review
|
|
63
|
+
/tfx-deep-plan "migrate REST to GraphQL"
|
|
64
|
+
|
|
65
|
+
# Debate — 3개의 독립적인 의견을 확보
|
|
66
|
+
/tfx-debate "Redis vs PostgreSQL LISTEN/NOTIFY for real-time events"
|
|
67
|
+
|
|
68
|
+
# Persistence — 완료될 때까지 멈추지 않음
|
|
69
|
+
/tfx-ralph "implement full auth flow with tests"
|
|
70
|
+
|
|
71
|
+
# Team — Multi-CLI 병렬 오케스트레이션
|
|
72
|
+
/tfx-multi "refactor auth + update UI + add tests"
|
|
73
|
+
|
|
74
|
+
# Remote — 원격 머신에 Claude 세션 생성
|
|
75
|
+
/tfx-remote-setup # 인터랙티브 호스트 설정 위저드 (Tailscale + SSH)
|
|
76
|
+
/tfx-remote-spawn "울트라에서 보안 리뷰 해" # 원격 호스트에서 세션 실행
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
43
81
|
## v8의 새로운 기능
|
|
44
82
|
|
|
45
83
|
**triflux v8**은 **Tri-CLI Consensus Intelligence**를 도입합니다. Claude, Codex, Gemini가 각각 독립적으로 분석한 뒤, 구조화된 토론을 거쳐 교차 검증하는 근본적으로 새로운 접근 방식입니다. 모든 Deep 스킬은 Anti-Herding(편향 오염 방지)과 Consensus Gate를 통한 출력 보장을 제공합니다.
|
|
@@ -171,7 +209,8 @@ Phase 3: Resolution (합의율 < 70%일 경우)
|
|
|
171
209
|
| `tfx-codex` | Codex 전용 오케스트레이터 |
|
|
172
210
|
| `tfx-gemini` | Gemini 전용 오케스트레이터 |
|
|
173
211
|
| `tfx-auto-codex` | Codex 주도 오케스트레이터 |
|
|
174
|
-
| `remote-spawn` | psmux를 통한 원격 세션 관리 |
|
|
212
|
+
| `tfx-remote-spawn` | psmux를 통한 원격 세션 관리 |
|
|
213
|
+
| `tfx-remote-setup` | 원격 호스트 설정 위저드 (Tailscale + SSH) |
|
|
175
214
|
|
|
176
215
|
---
|
|
177
216
|
|
package/README.md
CHANGED
|
@@ -17,16 +17,11 @@
|
|
|
17
17
|
<a href="https://www.npmjs.com/package/triflux"><img src="https://img.shields.io/npm/v/triflux?style=flat-square&color=FFAF00&label=npm" alt="npm version"></a>
|
|
18
18
|
<a href="https://www.npmjs.com/package/triflux"><img src="https://img.shields.io/npm/dm/triflux?style=flat-square&color=F5C242" alt="npm downloads"></a>
|
|
19
19
|
<a href="https://github.com/tellang/triflux/stargazers"><img src="https://img.shields.io/github/stars/tellang/triflux?style=flat-square&color=FFAF00" alt="GitHub stars"></a>
|
|
20
|
-
<a href="https://github.com/tellang/triflux/actions"><img src="https://img.shields.io/github/actions/workflow/status/tellang/triflux/ci.yml?style=flat-square&label=CI" alt="CI"></a>
|
|
21
20
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-374151?style=flat-square" alt="License: MIT"></a>
|
|
22
21
|
</p>
|
|
23
22
|
|
|
24
23
|
<p align="center">
|
|
25
|
-
<
|
|
26
|
-
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/demo-dark.gif">
|
|
27
|
-
<source media="(prefers-color-scheme: light)" srcset="docs/assets/demo-light.gif">
|
|
28
|
-
<img alt="triflux demo" src="docs/assets/demo-dark.gif" width="680">
|
|
29
|
-
</picture>
|
|
24
|
+
<img alt="triflux demo" src="docs/assets/demo-multi.gif" width="680">
|
|
30
25
|
</p>
|
|
31
26
|
|
|
32
27
|
<p align="center">
|
|
@@ -40,6 +35,49 @@
|
|
|
40
35
|
|
|
41
36
|
---
|
|
42
37
|
|
|
38
|
+
## Quick Start
|
|
39
|
+
|
|
40
|
+
### 1. Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g triflux
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Setup
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
tfx setup
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Use
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Light — single model, fast execution
|
|
56
|
+
/tfx-research "React 19 Server Actions best practices"
|
|
57
|
+
/tfx-review
|
|
58
|
+
/tfx-plan "add JWT auth middleware"
|
|
59
|
+
|
|
60
|
+
# Deep — 3-party consensus for critical work
|
|
61
|
+
/tfx-deep-research "microservice architecture comparison 2026"
|
|
62
|
+
/tfx-deep-review
|
|
63
|
+
/tfx-deep-plan "migrate REST to GraphQL"
|
|
64
|
+
|
|
65
|
+
# Debate — get 3 independent opinions
|
|
66
|
+
/tfx-debate "Redis vs PostgreSQL LISTEN/NOTIFY for real-time events"
|
|
67
|
+
|
|
68
|
+
# Persistence — don't stop until done
|
|
69
|
+
/tfx-ralph "implement full auth flow with tests"
|
|
70
|
+
|
|
71
|
+
# Team — Multi-CLI parallel orchestration
|
|
72
|
+
/tfx-multi "refactor auth + update UI + add tests"
|
|
73
|
+
|
|
74
|
+
# Remote — spawn Claude sessions on other machines
|
|
75
|
+
/tfx-remote-setup # interactive host wizard (Tailscale + SSH)
|
|
76
|
+
/tfx-remote-spawn "run security review on ultra4" # spawn on remote host
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
43
81
|
## What's New in v8
|
|
44
82
|
|
|
45
83
|
**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.
|
|
@@ -171,7 +209,8 @@ Phase 3: Resolution (if consensus < 70%)
|
|
|
171
209
|
| `tfx-codex` | Codex-only orchestrator |
|
|
172
210
|
| `tfx-gemini` | Gemini-only orchestrator |
|
|
173
211
|
| `tfx-auto-codex` | Codex-lead orchestrator |
|
|
174
|
-
| `remote-spawn` | Remote session management via psmux |
|
|
212
|
+
| `tfx-remote-spawn` | Remote session management via psmux |
|
|
213
|
+
| `tfx-remote-setup` | Remote host setup wizard (Tailscale + SSH) |
|
|
175
214
|
|
|
176
215
|
---
|
|
177
216
|
|
package/hub/team/ansi.mjs
CHANGED
|
@@ -65,16 +65,92 @@ export function color(text, fg, bg) {
|
|
|
65
65
|
export function bold(text) { return `${BOLD}${text}${RESET}`; }
|
|
66
66
|
export function dim(text) { return `${DIM}${text}${RESET}`; }
|
|
67
67
|
|
|
68
|
+
export function lerpRgb(a, b, t) {
|
|
69
|
+
return {
|
|
70
|
+
r: Math.round(a.r + (b.r - a.r) * t),
|
|
71
|
+
g: Math.round(a.g + (b.g - a.g) * t),
|
|
72
|
+
b: Math.round(a.b + (b.b - a.b) * t),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function rgbSeq(rgb, mode = 38) {
|
|
77
|
+
return `${ESC}[${mode};2;${rgb.r};${rgb.g};${rgb.b}m`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function brightenRgb(rgb, amount = 0.3) {
|
|
81
|
+
return lerpRgb(rgb, { r: 255, g: 255, b: 255 }, amount);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parseRgbSeq(seq) {
|
|
85
|
+
const match = typeof seq === "string"
|
|
86
|
+
? seq.match(/\x1b\[(?:38|48);2;(\d+);(\d+);(\d+)m/)
|
|
87
|
+
: null;
|
|
88
|
+
if (!match) return null;
|
|
89
|
+
return {
|
|
90
|
+
r: Number.parseInt(match[1], 10),
|
|
91
|
+
g: Number.parseInt(match[2], 10),
|
|
92
|
+
b: Number.parseInt(match[3], 10),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function reapplyBackground(text, bgSeq) {
|
|
97
|
+
if (!bgSeq) return text;
|
|
98
|
+
return `${bgSeq}${String(text).replaceAll(RESET, `${RESET}${bgSeq}`)}${RESET}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
68
101
|
// ── 박스 그리기 (유니코드 테두리) ──
|
|
69
102
|
const BOX = { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│", ml: "├", mr: "┤" };
|
|
70
103
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
104
|
+
function borderHighlightCell(width, totalRows, highlightPos) {
|
|
105
|
+
if (!Number.isFinite(highlightPos)) return null;
|
|
106
|
+
const perimeter = 2 * (width - 2) + 2 * totalRows;
|
|
107
|
+
if (perimeter <= 0) return null;
|
|
108
|
+
let pos = Math.floor(highlightPos) % perimeter;
|
|
109
|
+
if (pos < 0) pos += perimeter;
|
|
110
|
+
|
|
111
|
+
if (pos < width - 2) return { row: 0, col: pos + 1 };
|
|
112
|
+
pos -= width - 2;
|
|
113
|
+
if (pos < totalRows) return { row: pos, col: width - 1 };
|
|
114
|
+
pos -= totalRows;
|
|
115
|
+
if (pos < width - 2) return { row: totalRows - 1, col: width - 2 - pos };
|
|
116
|
+
pos -= width - 2;
|
|
117
|
+
return { row: totalRows - 1 - pos, col: 0 };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function renderBorderChar(glyph, row, col, highlightCell, borderSeq, highlightSeq) {
|
|
121
|
+
if (highlightCell && highlightCell.row === row && highlightCell.col === col) {
|
|
122
|
+
return `${highlightSeq}${glyph}${RESET}`;
|
|
123
|
+
}
|
|
124
|
+
return borderSeq ? `${borderSeq}${glyph}${RESET}` : glyph;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function box(lines, width, borderColor = "", options = {}) {
|
|
128
|
+
const isFn = typeof borderColor === "function";
|
|
129
|
+
const totalRows = lines.length + 2;
|
|
130
|
+
const bc = isFn ? (row) => borderColor(row, totalRows) : () => borderColor;
|
|
131
|
+
const rst = (isFn || borderColor) ? RESET : "";
|
|
132
|
+
const highlightCell = borderHighlightCell(width, totalRows, options.highlightPos);
|
|
133
|
+
const highlightSeq = options.highlightColor
|
|
134
|
+
|| (() => {
|
|
135
|
+
const parsed = parseRgbSeq(typeof borderColor === "string" ? borderColor : "");
|
|
136
|
+
return parsed ? rgbSeq(brightenRgb(parsed, 0.45)) : `${BOLD}${FG.white}`;
|
|
137
|
+
})();
|
|
138
|
+
const topChars = [BOX.tl, ...Array.from({ length: width - 2 }, () => BOX.h), BOX.tr];
|
|
139
|
+
const botChars = [BOX.bl, ...Array.from({ length: width - 2 }, () => BOX.h), BOX.br];
|
|
140
|
+
const top = topChars
|
|
141
|
+
.map((glyph, col) => renderBorderChar(glyph, 0, col, highlightCell, bc(0), highlightSeq))
|
|
142
|
+
.join("");
|
|
143
|
+
const bot = botChars
|
|
144
|
+
.map((glyph, col) => renderBorderChar(glyph, totalRows - 1, col, highlightCell, bc(totalRows - 1), highlightSeq))
|
|
145
|
+
.join("");
|
|
146
|
+
const mid = `${bc(Math.floor(totalRows / 2))}${BOX.ml}${BOX.h.repeat(width - 2)}${BOX.mr}${rst}`;
|
|
147
|
+
const body = lines.map((l, i) => {
|
|
148
|
+
const row = i + 1;
|
|
149
|
+
const content = options.titleFlashBg && i === 0
|
|
150
|
+
? reapplyBackground(padRight(l, width - 4), options.titleFlashBg)
|
|
151
|
+
: padRight(l, width - 4);
|
|
152
|
+
return `${renderBorderChar(BOX.v, row, 0, highlightCell, bc(row), highlightSeq)} ${content} ${renderBorderChar(BOX.v, row, width - 1, highlightCell, bc(row), highlightSeq)}`;
|
|
153
|
+
});
|
|
78
154
|
return { top, body, bot, mid };
|
|
79
155
|
}
|
|
80
156
|
|
|
@@ -205,6 +281,12 @@ export const MOCHA = {
|
|
|
205
281
|
surface0: `${ESC}[38;2;49;50;68m`, // #313244 surface0
|
|
206
282
|
};
|
|
207
283
|
|
|
284
|
+
const MOCHA_RGB = {
|
|
285
|
+
ok: { r: 166, g: 227, b: 161 },
|
|
286
|
+
partial: { r: 250, g: 179, b: 135 },
|
|
287
|
+
fail: { r: 243, g: 139, b: 168 },
|
|
288
|
+
};
|
|
289
|
+
|
|
208
290
|
// ── badge 헬퍼 ──
|
|
209
291
|
// statusBadge(status) → ANSI 색상 문자열
|
|
210
292
|
export function statusBadge(status) {
|
|
@@ -231,13 +313,48 @@ export function statusBadge(status) {
|
|
|
231
313
|
}
|
|
232
314
|
|
|
233
315
|
// ── 진행률 바 ──
|
|
234
|
-
// progressBar(percent, width) — percent: 0~100,
|
|
235
|
-
export function progressBar(percent, width = 20) {
|
|
316
|
+
// progressBar(percent, width, time) — percent: 0~100, time 전달 시 shimmer sweep
|
|
317
|
+
export function progressBar(percent, width = 20, time) {
|
|
318
|
+
const ratio = Math.max(0, Math.min(100, percent)) / 100;
|
|
319
|
+
const filled = Math.round(ratio * width);
|
|
320
|
+
const empty = width - filled;
|
|
321
|
+
const fillRgb = percent >= 100 ? MOCHA_RGB.ok : percent >= 50 ? MOCHA_RGB.partial : MOCHA_RGB.fail;
|
|
322
|
+
const fillColor = rgbSeq(fillRgb);
|
|
323
|
+
let fillText = "█".repeat(filled);
|
|
324
|
+
|
|
325
|
+
if (filled > 0 && Number.isFinite(time)) {
|
|
326
|
+
const shinePos = Math.min(
|
|
327
|
+
filled - 1,
|
|
328
|
+
Math.floor(((((time % 2000) + 2000) % 2000) / 2000) * filled),
|
|
329
|
+
);
|
|
330
|
+
const shineColor = rgbSeq(brightenRgb(fillRgb, 0.3));
|
|
331
|
+
fillText = Array.from({ length: filled }, (_, idx) =>
|
|
332
|
+
idx === shinePos ? `${shineColor}█${RESET}` : `${fillColor}█${RESET}`
|
|
333
|
+
).join("");
|
|
334
|
+
} else if (filled > 0) {
|
|
335
|
+
fillText = `${fillColor}${fillText}${RESET}`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const emptyText = empty > 0 ? `${MOCHA.border}${"░".repeat(empty)}${RESET}` : "";
|
|
339
|
+
return `${fillText}${emptyText}`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── 애니메이션 진행률 바 (shimmer sweep) ──
|
|
343
|
+
export function animatedProgressBar(percent, width = 20, tick = 0) {
|
|
236
344
|
const ratio = Math.max(0, Math.min(100, percent)) / 100;
|
|
237
345
|
const filled = Math.round(ratio * width);
|
|
238
346
|
const empty = width - filled;
|
|
239
|
-
|
|
240
|
-
|
|
347
|
+
if (filled === 0 || percent >= 100) return progressBar(percent, width);
|
|
348
|
+
const baseClr = percent >= 50 ? MOCHA.partial : MOCHA.fail;
|
|
349
|
+
const pos = tick % (filled + 3);
|
|
350
|
+
let bar = "";
|
|
351
|
+
for (let i = 0; i < filled; i++) {
|
|
352
|
+
const d = Math.abs(i - pos);
|
|
353
|
+
if (d === 0) bar += `${ESC}[97m█`;
|
|
354
|
+
else if (d === 1) bar += `${baseClr}▓`;
|
|
355
|
+
else bar += `${baseClr}█`;
|
|
356
|
+
}
|
|
357
|
+
return `${bar}${MOCHA.border}${"░".repeat(empty)}${RESET}`;
|
|
241
358
|
}
|
|
242
359
|
|
|
243
360
|
// ── 상태 아이콘 ──
|
|
@@ -253,3 +370,9 @@ export const CLI_ICON = {
|
|
|
253
370
|
gemini: `${FG.gemini}🔵${RESET}`,
|
|
254
371
|
claude: `${FG.claude}🟠${RESET}`,
|
|
255
372
|
};
|
|
373
|
+
|
|
374
|
+
// ── 로딩 도트 (braille spinner) ──
|
|
375
|
+
const BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
376
|
+
export function loadingDots(tick = 0, clr = MOCHA.thinking) {
|
|
377
|
+
return `${clr}${BRAILLE_FRAMES[tick % BRAILLE_FRAMES.length]}${RESET}`;
|
|
378
|
+
}
|