triflux 10.1.1 → 10.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.md +269 -168
- package/bin/triflux.mjs +88 -6
- package/hub/team/ansi.mjs +20 -1
- package/hub/team/tui-lite.mjs +16 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,15 +8,19 @@
|
|
|
8
8
|
</picture>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
|
+
<h3 align="center">Tri-CLI Orchestration with Consensus Intelligence</h3>
|
|
12
|
+
|
|
11
13
|
<p align="center">
|
|
12
|
-
<strong>
|
|
13
|
-
|
|
14
|
+
Route tasks across <strong>Claude + Codex + Gemini</strong> — 42 skills, natural language routing,<br>
|
|
15
|
+
cross-model review, and reflexion-based adaptive learning.
|
|
14
16
|
</p>
|
|
15
17
|
|
|
16
18
|
<p align="center">
|
|
17
19
|
<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
20
|
<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
21
|
<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>
|
|
22
|
+
<img src="https://img.shields.io/badge/skills-42-F5C242?style=flat-square" alt="42 skills">
|
|
23
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-374151?style=flat-square" alt="Node >= 18">
|
|
20
24
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-374151?style=flat-square" alt="License: MIT"></a>
|
|
21
25
|
</p>
|
|
22
26
|
|
|
@@ -25,16 +29,34 @@
|
|
|
25
29
|
</p>
|
|
26
30
|
|
|
27
31
|
<p align="center">
|
|
28
|
-
<a href="#quick-start">Quick Start</a>
|
|
29
|
-
<a href="#tri-cli-consensus">
|
|
30
|
-
<a href="#
|
|
31
|
-
<a href="#
|
|
32
|
-
<a href="#
|
|
32
|
+
<a href="#quick-start">Quick Start</a> ·
|
|
33
|
+
<a href="#tri-cli-consensus">Consensus Engine</a> ·
|
|
34
|
+
<a href="#42-skills">42 Skills</a> ·
|
|
35
|
+
<a href="#deep-vs-light">Deep vs Light</a> ·
|
|
36
|
+
<a href="#architecture">Architecture</a> ·
|
|
37
|
+
<a href="#under-the-hood">Under the Hood</a> ·
|
|
33
38
|
<a href="#security">Security</a>
|
|
34
39
|
</p>
|
|
35
40
|
|
|
36
41
|
---
|
|
37
42
|
|
|
43
|
+
## What is triflux?
|
|
44
|
+
|
|
45
|
+
Most AI coding tools talk to **one model**. triflux talks to **three** — and makes them argue.
|
|
46
|
+
|
|
47
|
+
Every Deep skill runs Claude, Codex, and Gemini **independently** (no cross-visibility), then cross-validates their findings. Only consensus-verified results survive. The result: **87% fewer false positives** compared to single-model review.
|
|
48
|
+
|
|
49
|
+
You don't need to memorize commands. Say what you want in natural language — triflux routes to the right skill automatically:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
"review this" → /tfx-review (Light — single model, fast)
|
|
53
|
+
"review this thoroughly" → /tfx-deep-review (Deep — 3-party consensus)
|
|
54
|
+
"리뷰해줘" → /tfx-review (Korean works too)
|
|
55
|
+
"제대로 리뷰해" → /tfx-deep-review (depth modifier detected)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
38
60
|
## Quick Start
|
|
39
61
|
|
|
40
62
|
### 1. Install
|
|
@@ -67,52 +89,72 @@ tfx setup
|
|
|
67
89
|
|
|
68
90
|
# Persistence — don't stop until done
|
|
69
91
|
/tfx-persist "implement full auth flow with tests"
|
|
70
|
-
# Compatibility alias
|
|
71
|
-
/tfx-ralph "implement full auth flow with tests"
|
|
72
92
|
|
|
73
|
-
# Team —
|
|
93
|
+
# Team — multi-CLI parallel orchestration
|
|
74
94
|
/tfx-multi "refactor auth + update UI + add tests"
|
|
75
95
|
|
|
96
|
+
# Monitor — real-time routing dashboard
|
|
97
|
+
tfx monitor
|
|
98
|
+
|
|
76
99
|
# Remote — spawn Claude sessions on other machines
|
|
77
|
-
/tfx-remote-setup
|
|
78
|
-
/tfx-remote-spawn "run security review on my-server"
|
|
100
|
+
/tfx-remote-setup # interactive host wizard
|
|
101
|
+
/tfx-remote-spawn "run security review on my-server"
|
|
79
102
|
```
|
|
80
103
|
|
|
104
|
+
> **Note**: Deep skills require **psmux** (or tmux), **triflux Hub**, **Codex CLI**, and **Gemini CLI** for full Tri-CLI consensus. Without these, skills automatically degrade to Claude-only mode. Run `tfx doctor` to check your environment.
|
|
105
|
+
|
|
81
106
|
---
|
|
82
107
|
|
|
83
|
-
## What's New
|
|
108
|
+
## What's New
|
|
109
|
+
|
|
110
|
+
### v10.1 — Reflexion Pipeline + TUI Monitor
|
|
84
111
|
|
|
85
|
-
|
|
112
|
+
| Feature | Description |
|
|
113
|
+
|---------|-------------|
|
|
114
|
+
| **TUI Routing Monitor** | `tfx monitor` — interactive terminal dashboard showing real-time skill routing, model selection, and success rates |
|
|
115
|
+
| **Reflexion Pipeline** | safety-guard events feed into a reflexion store, enabling adaptive learning from past routing decisions |
|
|
116
|
+
| **Adaptive Rules API v2** | Penalty promotion pipeline (`pending-penalties` → `adaptive_rules`), hit_count isolation, schema v2 with 18 tests |
|
|
117
|
+
| **Q-Learning Routing** | Experimental dynamic skill routing via Q-table weight optimization (`TRIFLUX_DYNAMIC_ROUTING=true`) |
|
|
118
|
+
| **Security Hardening** | headless-guard: wrapper bypass, pipe bypass, env escape vectors blocked. SSH bash-syntax forwarding prevention |
|
|
119
|
+
| **HUD System** | Codex plan-aware status display with correct bucket-to-slot mapping |
|
|
86
120
|
|
|
87
|
-
### v10
|
|
121
|
+
### v10.0 — 4-Lake Roadmap
|
|
122
|
+
|
|
123
|
+
<details>
|
|
124
|
+
<summary>Expand v10.0 details</summary>
|
|
88
125
|
|
|
89
126
|
- **Lake 1: CLI Stability** — Retry, stall detection, version cache. Zero silent failures
|
|
90
127
|
- **Lake 2: Plugin Isolation** — cli-adapter-base, team-bridge, pack.mjs sync
|
|
91
|
-
- **Lake 3: Remote Infrastructure** — SSH keepalive/retry, hosts.json capability routing,
|
|
128
|
+
- **Lake 3: Remote Infrastructure** — SSH keepalive/retry, hosts.json capability routing, MCP singleton daemon
|
|
92
129
|
- **Lake 4: Token Optimization** — Skill template engine, shared segments, manifest separation. 62% prompt token reduction
|
|
93
130
|
- **Lake 5: Agent Mesh** — Message routing, per-agent queues, heartbeat monitoring, Conductor integration
|
|
94
131
|
|
|
95
|
-
|
|
132
|
+
</details>
|
|
96
133
|
|
|
97
|
-
|
|
134
|
+
### v9 — Harness-Native Intelligence
|
|
98
135
|
|
|
99
|
-
|
|
136
|
+
<details>
|
|
137
|
+
<summary>Expand v9 details</summary>
|
|
100
138
|
|
|
101
|
-
- **Natural Language Routing** — Say "review this" or "리뷰해줘" instead of memorizing
|
|
102
|
-
- **Cross-Model Review** — Claude writes → Codex reviews.
|
|
103
|
-
- **Context Isolation** — Off-topic requests auto-detected; spawns a clean psmux session
|
|
104
|
-
- **
|
|
105
|
-
- **Codex Swarm Hardened** — PowerShell `.ps1` launchers, profile-based execution (no `--dangerously` flag), `/merge-worktree` auto-invocation for result collection
|
|
106
|
-
- **Skill Metadata** — Every skill labeled: wrapper/infrastructure/Light-Deep pairs. Trigger conflicts resolved
|
|
139
|
+
- **Natural Language Routing** — Say "review this" or "리뷰해줘" instead of memorizing skill names
|
|
140
|
+
- **Cross-Model Review** — Claude writes → Codex reviews. Same-model self-approve blocked
|
|
141
|
+
- **Context Isolation** — Off-topic requests auto-detected; spawns a clean psmux session
|
|
142
|
+
- **Codex Swarm Hardened** — PowerShell `.ps1` launchers, profile-based execution
|
|
107
143
|
|
|
108
|
-
|
|
144
|
+
</details>
|
|
109
145
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
146
|
+
### v8 — Tri-Debate Foundation
|
|
147
|
+
|
|
148
|
+
<details>
|
|
149
|
+
<summary>Expand v8 details</summary>
|
|
150
|
+
|
|
151
|
+
- **Tri-Debate Engine** — 3-CLI independent analysis with anti-herding and consensus scoring
|
|
152
|
+
- **Deep/Light Variants** — Every domain has both a fast mode and a thorough mode
|
|
113
153
|
- **Expert Panel** — Virtual expert simulation via `tfx-panel`
|
|
114
|
-
- **Hub IPC** —
|
|
115
|
-
- **psmux
|
|
154
|
+
- **Hub IPC** — Named Pipe & HTTP MCP bridge
|
|
155
|
+
- **psmux** — Windows Terminal native multiplexer
|
|
156
|
+
|
|
157
|
+
</details>
|
|
116
158
|
|
|
117
159
|
---
|
|
118
160
|
|
|
@@ -122,18 +164,18 @@ tfx setup
|
|
|
122
164
|
<img src="docs/assets/consensus-flow.svg" alt="Tri-CLI Consensus Flow" width="680">
|
|
123
165
|
</p>
|
|
124
166
|
|
|
125
|
-
The core innovation
|
|
167
|
+
The core innovation. Instead of trusting a single model, every Deep skill runs:
|
|
126
168
|
|
|
127
169
|
```
|
|
128
170
|
Phase 1: Independent Analysis (Anti-Herding)
|
|
129
|
-
├─ Claude Opus → Analysis A
|
|
130
|
-
├─ Codex CLI → Analysis B
|
|
131
|
-
└─ Gemini CLI → Analysis C
|
|
171
|
+
├─ Claude Opus → Analysis A (isolated, no cross-visibility)
|
|
172
|
+
├─ Codex CLI → Analysis B (isolated, no cross-visibility)
|
|
173
|
+
└─ Gemini CLI → Analysis C (isolated, no cross-visibility)
|
|
132
174
|
|
|
133
175
|
Phase 2: Cross-Validation
|
|
134
|
-
├─ Compare
|
|
135
|
-
├─
|
|
136
|
-
└─
|
|
176
|
+
├─ Compare findings across 3 sources
|
|
177
|
+
├─ 2/3+ agreement → CONSENSUS
|
|
178
|
+
└─ 1/3 only → DISPUTED (needs resolution)
|
|
137
179
|
|
|
138
180
|
Phase 3: Resolution (if consensus < 70%)
|
|
139
181
|
├─ Each CLI reviews opposing arguments
|
|
@@ -141,119 +183,117 @@ Phase 3: Resolution (if consensus < 70%)
|
|
|
141
183
|
└─ Unresolved → user decides
|
|
142
184
|
```
|
|
143
185
|
|
|
144
|
-
**
|
|
186
|
+
**v10.1 addition**: The **Reflexion Pipeline** feeds consensus outcomes back into an adaptive rules store, so routing decisions improve over time based on which models perform best for which task types.
|
|
145
187
|
|
|
146
188
|
---
|
|
147
189
|
|
|
148
|
-
##
|
|
190
|
+
## 42 Skills
|
|
149
191
|
|
|
150
|
-
### Research
|
|
192
|
+
### Research & Discovery
|
|
151
193
|
|
|
152
|
-
| Skill | Type | Description |
|
|
153
|
-
|
|
154
|
-
| `tfx-research` | Light | Quick web search via Exa/Brave/Tavily auto-selection |
|
|
155
|
-
| `tfx-deep-research` | Deep | Multi-source parallel search with 3-CLI cross-validation |
|
|
156
|
-
| `tfx-find` | Light | Fast codebase search — files, symbols, patterns
|
|
157
|
-
| `tfx-autoresearch` | Light | Autonomous web research to structured report |
|
|
194
|
+
| Skill | Type | Description |
|
|
195
|
+
|-------|------|-------------|
|
|
196
|
+
| `tfx-research` | Light | Quick web search via Exa/Brave/Tavily auto-selection |
|
|
197
|
+
| `tfx-deep-research` | Deep | Multi-source parallel search with 3-CLI cross-validation |
|
|
198
|
+
| `tfx-find` | Light | Fast codebase search — files, symbols, patterns |
|
|
199
|
+
| `tfx-autoresearch` | Light | Autonomous web research to structured report |
|
|
158
200
|
|
|
159
|
-
### Analysis
|
|
201
|
+
### Analysis & Planning
|
|
160
202
|
|
|
161
|
-
| Skill | Type | Description |
|
|
162
|
-
|
|
163
|
-
| `tfx-analysis` | Light | Quick code/architecture analysis
|
|
164
|
-
| `tfx-deep-analysis` | Deep | 3-perspective analysis
|
|
203
|
+
| Skill | Type | Description |
|
|
204
|
+
|-------|------|-------------|
|
|
205
|
+
| `tfx-analysis` | Light | Quick code/architecture analysis |
|
|
206
|
+
| `tfx-deep-analysis` | Deep | 3-perspective analysis with Tri-Debate consensus |
|
|
207
|
+
| `tfx-plan` | Light | Quick implementation plan |
|
|
208
|
+
| `tfx-deep-plan` | Deep | Planner + Architect + Critic consensus planning |
|
|
209
|
+
| `tfx-interview` | Light | Socratic requirements exploration |
|
|
210
|
+
| `tfx-deep-interview` | Deep | Deep interview with mathematical ambiguity gating |
|
|
165
211
|
|
|
166
212
|
### Execution
|
|
167
213
|
|
|
168
|
-
| Skill | Type | Description |
|
|
169
|
-
|
|
170
|
-
| `tfx-
|
|
171
|
-
| `tfx-
|
|
172
|
-
| `tfx-
|
|
173
|
-
|
|
174
|
-
### QA & Verification
|
|
175
|
-
|
|
176
|
-
| Skill | Type | Description | Tokens |
|
|
177
|
-
|-------|------|-------------|--------|
|
|
178
|
-
| `tfx-qa` | Light | Test → Fix → Retest cycle (max 3 rounds) | ~5K |
|
|
179
|
-
| `tfx-deep-qa` | Deep | 3-CLI independent verification with consensus scoring | ~25K |
|
|
214
|
+
| Skill | Type | Description |
|
|
215
|
+
|-------|------|-------------|
|
|
216
|
+
| `tfx-auto` | Router | Unified CLI orchestrator — auto-triage + command shortcuts |
|
|
217
|
+
| `tfx-autopilot` | Light | Single-file autonomous execution (<5min tasks) |
|
|
218
|
+
| `tfx-fullcycle` | Deep | Full pipeline: Design → Plan → Execute → QA → Verify |
|
|
180
219
|
|
|
181
|
-
###
|
|
220
|
+
### Review & QA
|
|
182
221
|
|
|
183
|
-
| Skill | Type | Description |
|
|
184
|
-
|
|
185
|
-
| `tfx-
|
|
186
|
-
| `tfx-deep-
|
|
222
|
+
| Skill | Type | Description |
|
|
223
|
+
|-------|------|-------------|
|
|
224
|
+
| `tfx-review` | Light | Quick code review |
|
|
225
|
+
| `tfx-deep-review` | Deep | 3-CLI independent review, consensus-only reporting |
|
|
226
|
+
| `tfx-qa` | Light | Test → Fix → Retest cycle (max 3 rounds) |
|
|
227
|
+
| `tfx-deep-qa` | Deep | 3-CLI independent verification with consensus scoring |
|
|
187
228
|
|
|
188
|
-
###
|
|
229
|
+
### Debate & Decision
|
|
189
230
|
|
|
190
|
-
| Skill | Type | Description |
|
|
191
|
-
|
|
192
|
-
| `tfx-
|
|
193
|
-
| `tfx-
|
|
231
|
+
| Skill | Type | Description |
|
|
232
|
+
|-------|------|-------------|
|
|
233
|
+
| `tfx-debate` | Deep | Structured 3-party debate on any topic |
|
|
234
|
+
| `tfx-panel` | Deep | Virtual expert panel simulation |
|
|
194
235
|
|
|
195
|
-
###
|
|
236
|
+
### Persistence & Routing
|
|
196
237
|
|
|
197
|
-
| Skill | Type | Description |
|
|
198
|
-
|
|
199
|
-
| `tfx-
|
|
200
|
-
| `tfx-
|
|
238
|
+
| Skill | Type | Description |
|
|
239
|
+
|-------|------|-------------|
|
|
240
|
+
| `tfx-persist` | Deep | 3-party verified loop until task completion |
|
|
241
|
+
| `tfx-ralph` | — | Alias for `tfx-persist` |
|
|
242
|
+
| `tfx-autoroute` | Light | Auto model escalation on failure |
|
|
243
|
+
| `tfx-auto-codex` | — | Codex-lead orchestrator |
|
|
201
244
|
|
|
202
|
-
###
|
|
245
|
+
### Orchestration & Infrastructure
|
|
203
246
|
|
|
204
|
-
| Skill |
|
|
205
|
-
|
|
206
|
-
| `tfx-
|
|
207
|
-
| `tfx-
|
|
208
|
-
| `tfx-
|
|
247
|
+
| Skill | Description |
|
|
248
|
+
|-------|-------------|
|
|
249
|
+
| `tfx-consensus` | Core consensus engine (used by all Deep skills) |
|
|
250
|
+
| `tfx-hub` | MCP message bus — Named Pipe & HTTP bridge |
|
|
251
|
+
| `tfx-multi` | Multi-CLI team orchestration (2+ parallel tasks) |
|
|
252
|
+
| `tfx-codex-swarm` | Parallel Codex sessions via worktree + psmux |
|
|
253
|
+
| `tfx-swarm` | Unified swarm orchestration |
|
|
254
|
+
| `tfx-codex` | Codex-only orchestrator |
|
|
255
|
+
| `tfx-gemini` | Gemini-only orchestrator |
|
|
209
256
|
|
|
210
|
-
###
|
|
257
|
+
### Remote
|
|
211
258
|
|
|
212
|
-
| Skill |
|
|
213
|
-
|
|
214
|
-
| `tfx-
|
|
215
|
-
| `tfx-
|
|
216
|
-
| `tfx-interview` | Light | Socratic requirements exploration | ~15K |
|
|
217
|
-
| `tfx-deep-interview` | Deep | Socratic deep interview with ambiguity gating | ~25K |
|
|
218
|
-
| `tfx-prune` | Light | AI slop removal — dead code, over-abstraction cleanup | ~10K |
|
|
259
|
+
| Skill | Description |
|
|
260
|
+
|-------|-------------|
|
|
261
|
+
| `tfx-remote-spawn` | Spawn Claude sessions on remote machines via SSH |
|
|
262
|
+
| `tfx-remote-setup` | Interactive host wizard (Tailscale + SSH discovery) |
|
|
219
263
|
|
|
220
|
-
###
|
|
264
|
+
### Meta & Tooling
|
|
221
265
|
|
|
222
266
|
| Skill | Description |
|
|
223
267
|
|-------|-------------|
|
|
224
|
-
| `tfx-
|
|
225
|
-
| `tfx-
|
|
226
|
-
| `tfx-
|
|
227
|
-
| `tfx-codex-swarm` | Parallel Codex sessions via worktree + psmux |
|
|
228
|
-
| `tfx-swarm` | Unified swarm orchestration |
|
|
268
|
+
| `tfx-index` | Project indexing — 94% token reduction (58K → 3K) |
|
|
269
|
+
| `tfx-forge` | Create new skills interactively |
|
|
270
|
+
| `tfx-prune` | AI slop removal — dead code, over-abstraction cleanup |
|
|
229
271
|
| `tfx-setup` | Initial setup wizard |
|
|
230
272
|
| `tfx-doctor` | Diagnostics and auto-repair |
|
|
231
273
|
| `tfx-hooks` | Claude Code hook priority manager |
|
|
232
274
|
| `tfx-profile` | Codex/Gemini CLI profile management |
|
|
233
|
-
| `tfx-
|
|
234
|
-
| `
|
|
235
|
-
| `
|
|
236
|
-
| `tfx-remote-spawn` | Remote session management via psmux + SSH |
|
|
237
|
-
| `tfx-remote-setup` | Remote host setup wizard (Tailscale + SSH) |
|
|
275
|
+
| `tfx-psmux-rules` | psmux command generation rules |
|
|
276
|
+
| `merge-worktree` | Worktree merge helper for swarm results |
|
|
277
|
+
| `star-prompt` | GitHub star prompt for postinstall |
|
|
238
278
|
|
|
239
279
|
---
|
|
240
280
|
|
|
241
281
|
## Deep vs Light
|
|
242
282
|
|
|
243
|
-
Every domain offers both modes:
|
|
244
|
-
|
|
245
283
|
<p align="center">
|
|
246
284
|
<img src="docs/assets/deep-vs-light.svg" alt="Deep vs Light comparison" width="680">
|
|
247
285
|
</p>
|
|
248
286
|
|
|
287
|
+
Every domain offers both modes. Depth modifiers in natural language auto-escalate:
|
|
288
|
+
|
|
249
289
|
| Dimension | Light | Deep |
|
|
250
290
|
|-----------|-------|------|
|
|
251
|
-
| **
|
|
252
|
-
| **Tokens** | 3K
|
|
291
|
+
| **Models** | Single (usually Codex) | 3-party (Claude + Codex + Gemini) |
|
|
292
|
+
| **Tokens** | 3K–15K | 20K–80K |
|
|
253
293
|
| **Speed** | Seconds | Minutes |
|
|
254
294
|
| **Accuracy** | Good (single perspective) | Excellent (consensus-verified) |
|
|
255
295
|
| **Bias** | Possible | Eliminated via anti-herding |
|
|
256
|
-
| **
|
|
296
|
+
| **Trigger** | Default, "quick", "fast" | "thoroughly", "carefully", "제대로" |
|
|
257
297
|
|
|
258
298
|
---
|
|
259
299
|
|
|
@@ -264,11 +304,11 @@ Every domain offers both modes:
|
|
|
264
304
|
</p>
|
|
265
305
|
|
|
266
306
|
<details>
|
|
267
|
-
<summary>Interactive diagram
|
|
307
|
+
<summary>Interactive diagram</summary>
|
|
268
308
|
|
|
269
309
|
```mermaid
|
|
270
310
|
graph TD
|
|
271
|
-
User([User / Claude Code]) <-->|Skills &
|
|
311
|
+
User([User / Claude Code]) <-->|"Skills & Natural Language"| TFX[tfx Skills Layer]
|
|
272
312
|
TFX <-->|Consensus Engine| CONSENSUS[tfx-consensus]
|
|
273
313
|
|
|
274
314
|
subgraph "Tri-CLI Consensus"
|
|
@@ -284,14 +324,16 @@ graph TD
|
|
|
284
324
|
RESOLVE --> MERGE
|
|
285
325
|
end
|
|
286
326
|
|
|
287
|
-
TFX <-->|Named Pipe / HTTP| HUB[triflux Hub
|
|
327
|
+
TFX <-->|Named Pipe / HTTP| HUB[triflux Hub]
|
|
288
328
|
|
|
289
|
-
subgraph "
|
|
329
|
+
subgraph "Hub Services"
|
|
290
330
|
HUB <--> STORE[(SQLite Store)]
|
|
291
|
-
HUB <-->
|
|
292
|
-
HUB <-->
|
|
331
|
+
HUB <--> REFLEXION[Reflexion Engine]
|
|
332
|
+
HUB <--> ADAPTIVE[Adaptive Rules]
|
|
333
|
+
HUB <--> MONITOR[TUI Monitor]
|
|
293
334
|
end
|
|
294
335
|
|
|
336
|
+
REFLEXION -->|"Feedback Loop"| TFX
|
|
295
337
|
HUB -.->|MCP Bridge| External[External MCP Clients]
|
|
296
338
|
```
|
|
297
339
|
|
|
@@ -299,95 +341,154 @@ graph TD
|
|
|
299
341
|
|
|
300
342
|
---
|
|
301
343
|
|
|
302
|
-
##
|
|
344
|
+
## Under the Hood
|
|
303
345
|
|
|
304
|
-
###
|
|
346
|
+
### Singleton MCP Hub with Dual-Protocol IPC
|
|
347
|
+
|
|
348
|
+
triflux Hub runs as a **singleton daemon** per machine. A filesystem lock prevents duplicate instances.
|
|
305
349
|
|
|
306
|
-
```
|
|
307
|
-
|
|
350
|
+
```
|
|
351
|
+
Local agents ──→ Named Pipe (NDJSON, sub-ms latency) ──→ Hub
|
|
352
|
+
Remote/Dashboard ──→ HTTP/REST ──────────────────────→ Hub
|
|
308
353
|
```
|
|
309
354
|
|
|
310
|
-
|
|
355
|
+
The bridge client tries Named Pipe first and falls back to HTTP automatically. Sessions auto-expire after 30 minutes, and the Hub self-terminates when idle. Run `tfx hub ensure` to guarantee the Hub is alive from any context.
|
|
311
356
|
|
|
312
|
-
|
|
313
|
-
|
|
357
|
+
### Reflexion Adaptive Learning
|
|
358
|
+
|
|
359
|
+
Errors become knowledge automatically. The Reflexion Engine runs a closed-loop learning pipeline:
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
safety-guard blocks command
|
|
363
|
+
→ error normalized (paths, timestamps, UUIDs stripped)
|
|
364
|
+
→ pattern stored in pending-penalties
|
|
365
|
+
→ promoted to adaptive rule (Bayesian confidence scoring)
|
|
366
|
+
→ injected into CLAUDE.md when confidence > threshold
|
|
367
|
+
|
|
368
|
+
Three-tier memory:
|
|
369
|
+
Tier 1 (Session) → cleared on session end
|
|
370
|
+
Tier 2 (Project) → decays -0.2 confidence per 5 unobserved sessions
|
|
371
|
+
Tier 3 (Permanent) → auto-injected into CLAUDE.md as machine-readable rules
|
|
314
372
|
```
|
|
315
373
|
|
|
316
|
-
|
|
374
|
+
A blocked command in Session 1 becomes a proactive warning in Session 2 and eventually a permanent instruction. Your AI agent literally gets smarter over time.
|
|
317
375
|
|
|
318
|
-
|
|
319
|
-
# Light — Quick single-model execution
|
|
320
|
-
/tfx-research "React 19 Server Actions best practices"
|
|
321
|
-
/tfx-review
|
|
322
|
-
/tfx-plan "add JWT auth middleware"
|
|
376
|
+
### Pipeline Quality Gates
|
|
323
377
|
|
|
324
|
-
|
|
325
|
-
/tfx-deep-research "microservice architecture comparison 2026"
|
|
326
|
-
/tfx-deep-review
|
|
327
|
-
/tfx-deep-plan "migrate REST to GraphQL"
|
|
378
|
+
Every Deep task runs through a **10-phase state machine** with quality gates:
|
|
328
379
|
|
|
329
|
-
|
|
330
|
-
|
|
380
|
+
```
|
|
381
|
+
plan → PRD → confidence gate → execute → deslop → verify → selfcheck → complete
|
|
382
|
+
↓
|
|
383
|
+
fix (max 3) → retry
|
|
384
|
+
```
|
|
331
385
|
|
|
332
|
-
|
|
333
|
-
|
|
386
|
+
- **Confidence Gate** (pre-execution): 5 weighted criteria must score >= 90% before execution starts
|
|
387
|
+
- **Hallucination Detection** (post-execution): 7 regex patterns catch AI claims without evidence:
|
|
388
|
+
- "tests pass" without test output
|
|
389
|
+
- "performance improved" without benchmarks
|
|
390
|
+
- "backward compatible" without verification
|
|
391
|
+
- "no changes needed" when diff exists
|
|
392
|
+
- **Bounded loops**: Fix attempts capped at 3, ralph iterations at 10. State persists in SQLite for crash recovery.
|
|
334
393
|
|
|
335
|
-
|
|
336
|
-
|
|
394
|
+
### 5-Tier Adaptive HUD
|
|
395
|
+
|
|
396
|
+
The Claude Code status bar auto-adapts to any terminal width:
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
full (120+ cols) ██████░░░░ claude 52% ██████░░░░ codex 48% savings: $2.40
|
|
400
|
+
compact (80 cols) c:52% x:48% g:Free sv:$2.40 CTX:67%
|
|
401
|
+
minimal (60 cols) c:52% x:48% sv:$2.40
|
|
402
|
+
micro (<60 cols) c52 x48 sv$2
|
|
403
|
+
nano (<40 cols) c:52%/x:48%
|
|
337
404
|
```
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
405
|
+
|
|
406
|
+
Zero config. Open a vertical split pane and the HUD auto-collapses. Close it and it expands back. When `tfx-multi` is active, a live worker row appears showing per-CLI progress: `x✓ g⋯ c✗` (completed/running/failed).
|
|
407
|
+
|
|
408
|
+
Context token attribution tracks usage by skill, file, and tool call, with warnings at 60%/80%/90% context fill.
|
|
409
|
+
|
|
410
|
+
### Windows Terminal Orchestration
|
|
411
|
+
|
|
412
|
+
triflux doesn't just run in a terminal -- it **orchestrates** it. The WT Manager API provides:
|
|
413
|
+
|
|
414
|
+
- **Tab creation** with PID-tracked lifecycle (temp file polling for readiness)
|
|
415
|
+
- **Split-pane layouts** via `applySplitLayout()` for multi-agent dashboards
|
|
416
|
+
- **Dead tab pruning** using cross-platform PID liveness detection
|
|
417
|
+
- **Base64 PowerShell encoding** eliminating all quoting/escaping issues
|
|
418
|
+
|
|
419
|
+
Every direct `wt.exe` call is blocked by safety-guard. Agents can only use the managed API path, preventing uncontrolled terminal sprawl.
|
|
341
420
|
|
|
342
421
|
---
|
|
343
422
|
|
|
344
|
-
##
|
|
423
|
+
## TUI Routing Monitor
|
|
345
424
|
|
|
346
|
-
|
|
425
|
+
**New in v10.1** — `tfx monitor` launches an interactive terminal dashboard:
|
|
347
426
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
427
|
+
```
|
|
428
|
+
┌─ Routing Monitor ─────────────────────────────────────────┐
|
|
429
|
+
│ │
|
|
430
|
+
│ Active Skills Success Rate Avg Latency Model │
|
|
431
|
+
│ ───────────── ──────────── ─────────── ───── │
|
|
432
|
+
│ tfx-review 94.2% 3.2s codex │
|
|
433
|
+
│ tfx-auto 87.1% 5.8s mixed │
|
|
434
|
+
│ tfx-research 91.0% 4.1s claude │
|
|
435
|
+
│ │
|
|
436
|
+
│ Reflexion Store: 142 rules │ Adaptive: 28 promoted │
|
|
437
|
+
│ Q-Table entries: 89 │ Pending penalties: 3 │
|
|
438
|
+
│ │
|
|
439
|
+
└───────────────────────────────────────────────────────────┘
|
|
440
|
+
```
|
|
359
441
|
|
|
360
|
-
|
|
442
|
+
The monitor visualizes:
|
|
443
|
+
- Real-time skill routing decisions and model selection
|
|
444
|
+
- Success/failure rates per skill and per model
|
|
445
|
+
- Reflexion store growth and adaptive rule promotions
|
|
446
|
+
- Q-Learning weight evolution (when `TRIFLUX_DYNAMIC_ROUTING=true`)
|
|
361
447
|
|
|
362
448
|
---
|
|
363
449
|
|
|
364
450
|
## Security
|
|
365
451
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
452
|
+
| Layer | Protection |
|
|
453
|
+
|-------|-----------|
|
|
454
|
+
| **Hub Token Auth** | Secure IPC via `TFX_HUB_TOKEN` (Bearer Auth) |
|
|
455
|
+
| **Localhost Binding** | Hub defaults to `127.0.0.1` only |
|
|
456
|
+
| **CORS Lockdown** | Strict origin checking for QoS Dashboard |
|
|
457
|
+
| **headless-guard** | Blocks direct `codex exec` / `gemini -y` outside tfx skills. Wrapper bypass, pipe bypass, env escape vectors all covered |
|
|
458
|
+
| **safety-guard** | SSH bash-syntax forwarding prevention, injection-safe shell execution |
|
|
459
|
+
| **Consensus Verification** | Deep skills prevent single-model hallucination via 3-party consensus |
|
|
460
|
+
| **Reflexion Feedback** | Security events feed adaptive rules for continuous improvement |
|
|
371
461
|
|
|
372
462
|
---
|
|
373
463
|
|
|
374
464
|
## Platform Support
|
|
375
465
|
|
|
376
|
-
|
|
377
|
-
|
|
466
|
+
| Platform | Multiplexer | Status |
|
|
467
|
+
|----------|-------------|--------|
|
|
468
|
+
| **Windows** | psmux (PowerShell) + Windows Terminal | Full support (CP949 encoding handled) |
|
|
469
|
+
| **Linux** | tmux | Full support |
|
|
470
|
+
| **macOS** | tmux | Full support |
|
|
378
471
|
|
|
379
472
|
---
|
|
380
473
|
|
|
381
|
-
##
|
|
474
|
+
## Research Foundation
|
|
475
|
+
|
|
476
|
+
The triflux skill suite was shaped by patterns from across the Claude Code ecosystem:
|
|
382
477
|
|
|
383
|
-
|
|
478
|
+
| Project | Inspiration |
|
|
479
|
+
|---------|-------------|
|
|
480
|
+
| everything-claude-code | Instinct-based learning patterns |
|
|
481
|
+
| Superpowers | TDD enforcement, composable skills |
|
|
482
|
+
| oh-my-openagent | Category routing, Hashline edits |
|
|
483
|
+
| SuperClaude | index-repo 94% token reduction, expert panels |
|
|
484
|
+
| oh-my-claudecode | Ralph persistence, CCG tri-model |
|
|
485
|
+
| ruflo | 60+ agent orchestration |
|
|
486
|
+
| Exa / Brave / Tavily MCP | Neural search, deep research pipeline |
|
|
384
487
|
|
|
385
|
-
-
|
|
386
|
-
- **Token Savings** — Real-time tracking of Claude tokens saved
|
|
387
|
-
- **Consensus Metrics** — Track agreement rates across CLIs
|
|
488
|
+
5-language research (EN/CN/RU/JP/UA) uncovered unique patterns: WeChat integration (CN), Discord mobile bridges (JP), GigaCode alternatives (RU), and community-driven localization efforts.
|
|
388
489
|
|
|
389
490
|
---
|
|
390
491
|
|
|
391
492
|
<p align="center">
|
|
392
|
-
<sub>MIT License
|
|
493
|
+
<sub>MIT License · Made by <a href="https://github.com/tellang">tellang</a></sub>
|
|
393
494
|
</p>
|
package/bin/triflux.mjs
CHANGED
|
@@ -171,11 +171,12 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
|
|
|
171
171
|
},
|
|
172
172
|
},
|
|
173
173
|
hub: {
|
|
174
|
-
usage: "tfx hub <start|stop|status> [--port N] [--json]",
|
|
174
|
+
usage: "tfx hub <start|stop|status|ensure> [--port N] [--json]",
|
|
175
175
|
description: "tfx-hub 프로세스 제어",
|
|
176
176
|
subcommands: {
|
|
177
177
|
start: { usage: "tfx hub start [--port N]" },
|
|
178
178
|
stop: { usage: "tfx hub stop" },
|
|
179
|
+
ensure: { usage: "tfx hub ensure [--port N] [--json]", description: "헬스체크 + 자동 시작 (idempotent)" },
|
|
179
180
|
status: {
|
|
180
181
|
usage: "tfx hub status [--json]",
|
|
181
182
|
options: [{ name: "--json", type: "boolean", description: "허브 상태를 JSON으로 출력" }],
|
|
@@ -3840,12 +3841,93 @@ async function cmdHub(args = [], options = {}) {
|
|
|
3840
3841
|
break;
|
|
3841
3842
|
}
|
|
3842
3843
|
|
|
3844
|
+
case "ensure": {
|
|
3845
|
+
// 사일런트 idempotent 보장 — 스킬 환경 프로브용.
|
|
3846
|
+
// Hub 살아있으면 즉시 종료, 죽어있으면 자동 시작 + ready 대기.
|
|
3847
|
+
const portArg = args.indexOf("--port");
|
|
3848
|
+
const ensurePort = portArg !== -1 ? args[portArg + 1] : (process.env.TFX_HUB_PORT || "27888");
|
|
3849
|
+
|
|
3850
|
+
// 1. 이미 healthy?
|
|
3851
|
+
const ensureProbed = await probeHubStatus("127.0.0.1", Number(ensurePort), 1500);
|
|
3852
|
+
if (ensureProbed?.hub?.state === "healthy") {
|
|
3853
|
+
if (json) printJson({ status: "ok", pid: ensureProbed.pid, port: Number(ensurePort) });
|
|
3854
|
+
else process.stdout.write("hub: ok\n");
|
|
3855
|
+
return;
|
|
3856
|
+
}
|
|
3857
|
+
|
|
3858
|
+
// 2. PID 파일 있는데 프로세스 죽었으면 정리
|
|
3859
|
+
if (existsSync(HUB_PID_FILE)) {
|
|
3860
|
+
try {
|
|
3861
|
+
const staleInfo = JSON.parse(readFileSync(HUB_PID_FILE, "utf8"));
|
|
3862
|
+
process.kill(staleInfo.pid, 0);
|
|
3863
|
+
// 프로세스 살아있지만 healthy가 아님 — 잠시 더 대기
|
|
3864
|
+
const retryDeadline = Date.now() + 3000;
|
|
3865
|
+
while (Date.now() < retryDeadline) {
|
|
3866
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
3867
|
+
const retry = await probeHubStatus("127.0.0.1", Number(ensurePort), 1000);
|
|
3868
|
+
if (retry?.hub?.state === "healthy") {
|
|
3869
|
+
if (json) printJson({ status: "ok", pid: retry.pid, port: Number(ensurePort) });
|
|
3870
|
+
else process.stdout.write("hub: ok\n");
|
|
3871
|
+
return;
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
} catch {
|
|
3875
|
+
try { unlinkSync(HUB_PID_FILE); } catch {}
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
// 3. 시작
|
|
3880
|
+
const serverPath = join(PKG_ROOT, "hub", "server.mjs");
|
|
3881
|
+
if (!existsSync(serverPath)) {
|
|
3882
|
+
if (json) printJson({ status: "error", reason: "server_missing" });
|
|
3883
|
+
else process.stderr.write("hub: server.mjs not found\n");
|
|
3884
|
+
process.exitCode = 1;
|
|
3885
|
+
return;
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
if (process.platform === "win32") {
|
|
3889
|
+
const child = spawn("cmd.exe", ["/c", "start", "/b", "", process.execPath, serverPath], {
|
|
3890
|
+
env: { ...process.env, TFX_HUB_PORT: String(ensurePort) },
|
|
3891
|
+
stdio: "ignore",
|
|
3892
|
+
windowsHide: true,
|
|
3893
|
+
});
|
|
3894
|
+
child.unref();
|
|
3895
|
+
} else {
|
|
3896
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
3897
|
+
env: { ...process.env, TFX_HUB_PORT: String(ensurePort) },
|
|
3898
|
+
detached: true,
|
|
3899
|
+
stdio: "ignore",
|
|
3900
|
+
});
|
|
3901
|
+
child.unref();
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
// 4. ready 대기 (최대 5초)
|
|
3905
|
+
const readyDeadline = Date.now() + 5000;
|
|
3906
|
+
while (Date.now() < readyDeadline) {
|
|
3907
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
3908
|
+
if (existsSync(HUB_PID_FILE)) {
|
|
3909
|
+
const readyProbe = await probeHubStatus("127.0.0.1", Number(ensurePort), 1000);
|
|
3910
|
+
if (readyProbe?.hub?.state === "healthy") {
|
|
3911
|
+
if (json) printJson({ status: "ok", pid: readyProbe.pid, port: Number(ensurePort), started: true });
|
|
3912
|
+
else process.stdout.write("hub: started\n");
|
|
3913
|
+
return;
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
// 5. 타임아웃이지만 프로세스는 기동 중일 수 있음
|
|
3919
|
+
if (json) printJson({ status: "starting", port: Number(ensurePort) });
|
|
3920
|
+
else process.stdout.write("hub: starting\n");
|
|
3921
|
+
break;
|
|
3922
|
+
}
|
|
3923
|
+
|
|
3843
3924
|
default:
|
|
3844
3925
|
console.log(`\n ${AMBER}${BOLD}⬡ tfx-hub${RESET}\n`);
|
|
3845
|
-
console.log(` ${WHITE_BRIGHT}tfx hub start${RESET}
|
|
3846
|
-
console.log(` ${DIM} --port N${RESET}
|
|
3847
|
-
console.log(` ${WHITE_BRIGHT}tfx hub stop${RESET}
|
|
3848
|
-
console.log(` ${WHITE_BRIGHT}tfx hub status${RESET}
|
|
3926
|
+
console.log(` ${WHITE_BRIGHT}tfx hub start${RESET} ${GRAY}허브 데몬 시작${RESET}`);
|
|
3927
|
+
console.log(` ${DIM} --port N${RESET} ${GRAY}포트 지정 (기본 27888)${RESET}`);
|
|
3928
|
+
console.log(` ${WHITE_BRIGHT}tfx hub stop${RESET} ${GRAY}허브 중지${RESET}`);
|
|
3929
|
+
console.log(` ${WHITE_BRIGHT}tfx hub status${RESET} ${GRAY}상태 확인${RESET}`);
|
|
3930
|
+
console.log(` ${WHITE_BRIGHT}tfx hub ensure${RESET} ${GRAY}헬스체크 + 자동 시작 (스킬 프로브용)${RESET}\n`);
|
|
3849
3931
|
}
|
|
3850
3932
|
}
|
|
3851
3933
|
|
|
@@ -3886,7 +3968,7 @@ async function main() {
|
|
|
3886
3968
|
cmdHandoff(cmdArgs, { json: JSON_OUTPUT });
|
|
3887
3969
|
return;
|
|
3888
3970
|
case "hub":
|
|
3889
|
-
await cmdHub(cmdArgs, { json: JSON_OUTPUT && (cmdArgs[0] || "status")
|
|
3971
|
+
await cmdHub(cmdArgs, { json: JSON_OUTPUT && ["status", "ensure"].includes(cmdArgs[0] || "status") });
|
|
3890
3972
|
return;
|
|
3891
3973
|
case "monitor": {
|
|
3892
3974
|
const { createMonitor } = await import("../tui/monitor.mjs");
|
package/hub/team/ansi.mjs
CHANGED
|
@@ -128,9 +128,28 @@ function renderBorderChar(glyph, row, col, highlightCell, borderSeq, highlightSe
|
|
|
128
128
|
export function box(lines, width, borderColor = "", options = {}) {
|
|
129
129
|
const isFn = typeof borderColor === "function";
|
|
130
130
|
const totalRows = lines.length + 2;
|
|
131
|
+
const highlightCell = borderHighlightCell(width, totalRows, options.highlightPos);
|
|
132
|
+
|
|
133
|
+
// Fast path: static border, no highlight — batch border chars (~13x less output)
|
|
134
|
+
if (!highlightCell && !isFn) {
|
|
135
|
+
const bc = borderColor || "";
|
|
136
|
+
const rst = bc ? RESET : "";
|
|
137
|
+
const hLine = BOX.h.repeat(Math.max(0, width - 2));
|
|
138
|
+
const top = `${bc}${BOX.tl}${hLine}${BOX.tr}${rst}`;
|
|
139
|
+
const bot = `${bc}${BOX.bl}${hLine}${BOX.br}${rst}`;
|
|
140
|
+
const mid = `${bc}${BOX.ml}${hLine}${BOX.mr}${rst}`;
|
|
141
|
+
const body = lines.map((l, i) => {
|
|
142
|
+
const content = options.titleFlashBg && i === 0
|
|
143
|
+
? reapplyBackground(padRight(l, width - 4), options.titleFlashBg)
|
|
144
|
+
: padRight(l, width - 4);
|
|
145
|
+
return `${bc}${BOX.v}${rst} ${content} ${bc}${BOX.v}${rst}`;
|
|
146
|
+
});
|
|
147
|
+
return { top, body, bot, mid };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Slow path: per-character rendering for highlight animation
|
|
131
151
|
const bc = isFn ? (row) => borderColor(row, totalRows) : () => borderColor;
|
|
132
152
|
const rst = (isFn || borderColor) ? RESET : "";
|
|
133
|
-
const highlightCell = borderHighlightCell(width, totalRows, options.highlightPos);
|
|
134
153
|
const highlightSeq = options.highlightColor
|
|
135
154
|
|| (() => {
|
|
136
155
|
const parsed = parseRgbSeq(typeof borderColor === "string" ? borderColor : "");
|
package/hub/team/tui-lite.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { altScreenOff, altScreenOn, BG, bold, box, clearScreen, clearToEnd, color, cursorHide, cursorHome, cursorShow, dim, eraseBelow, FG, MOCHA, padRight, progressBar, statusBadge, stripAnsi, truncate, wcswidth } from "./ansi.mjs";
|
|
1
|
+
import { altScreenOff, altScreenOn, BG, bold, box, clearScreen, clearToEnd, color, cursorHide, cursorHome, cursorShow, dim, eraseBelow, FG, MOCHA, moveTo, padRight, progressBar, statusBadge, stripAnsi, truncate, wcswidth } from "./ansi.mjs";
|
|
2
2
|
|
|
3
3
|
const FALLBACK_COLUMNS = 100, FALLBACK_ROWS = 24;
|
|
4
4
|
const VALID_TABS = new Set(["log", "detail", "files"]);
|
|
@@ -209,6 +209,7 @@ export function createLiteDashboard(opts = {}) {
|
|
|
209
209
|
let detailExpanded = true;
|
|
210
210
|
let focusTab = "log";
|
|
211
211
|
let helpVisible = false;
|
|
212
|
+
let prevFrame = [];
|
|
212
213
|
let inputAttached = false;
|
|
213
214
|
let rawModeEnabled = false;
|
|
214
215
|
|
|
@@ -297,7 +298,7 @@ export function createLiteDashboard(opts = {}) {
|
|
|
297
298
|
|
|
298
299
|
function attachInput() {
|
|
299
300
|
if (inputAttached) return;
|
|
300
|
-
if (!
|
|
301
|
+
if (!input?.isTTY || typeof input?.on !== "function") return;
|
|
301
302
|
inputAttached = true;
|
|
302
303
|
if (typeof input.setRawMode === "function") {
|
|
303
304
|
input.setRawMode(true);
|
|
@@ -337,8 +338,19 @@ export function createLiteDashboard(opts = {}) {
|
|
|
337
338
|
const rowsOut = buildRows();
|
|
338
339
|
if (isTTY) {
|
|
339
340
|
const width = viewportColumns();
|
|
340
|
-
const padded = rowsOut.map((line) => padRight(String(line ?? ""), width)
|
|
341
|
-
|
|
341
|
+
const padded = rowsOut.map((line) => padRight(String(line ?? ""), width));
|
|
342
|
+
// Diff-based rendering: only rewrite lines that actually changed
|
|
343
|
+
let buf = "";
|
|
344
|
+
for (let i = 0; i < padded.length; i++) {
|
|
345
|
+
if (padded[i] !== prevFrame[i]) {
|
|
346
|
+
buf += moveTo(i + 1, 1) + padded[i] + clearToEnd;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (prevFrame.length > padded.length) {
|
|
350
|
+
buf += moveTo(padded.length + 1, 1) + eraseBelow;
|
|
351
|
+
}
|
|
352
|
+
if (buf) write(buf);
|
|
353
|
+
prevFrame = padded;
|
|
342
354
|
} else write(`${rowsOut.join("\n")}\n`);
|
|
343
355
|
}
|
|
344
356
|
|