triflux 10.3.4 → 10.7.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/LICENSE +21 -21
- package/bin/tfx-doctor-tui.mjs +1 -1
- package/bin/tfx-doctor.mjs +6 -1
- package/bin/tfx-profile.mjs +1 -1
- package/bin/tfx-setup-tui.mjs +1 -1
- package/bin/tfx-setup.mjs +6 -1
- package/bin/triflux.mjs +2396 -1140
- package/hooks/agent-route-guard.mjs +12 -8
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +19 -7
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +108 -24
- package/hooks/hook-registry.json +11 -0
- package/hooks/keyword-rules.json +6 -10
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/pipeline-stop.mjs +3 -6
- package/hooks/safety-guard.mjs +99 -28
- package/hooks/session-start-fast.mjs +143 -0
- package/hooks/subagent-verifier.mjs +5 -4
- package/hub/account-broker.mjs +256 -60
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +95 -57
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +67 -30
- package/hub/bridge.mjs +0 -1
- package/hub/cli-adapter-base.mjs +200 -48
- package/hub/codex-adapter.mjs +76 -96
- package/hub/codex-compat.mjs +3 -3
- package/hub/codex-preflight.mjs +63 -37
- package/hub/delegator/contracts.mjs +19 -23
- package/hub/delegator/index.mjs +3 -3
- package/hub/delegator/service.mjs +88 -64
- package/hub/delegator/tool-definitions.mjs +5 -5
- package/hub/fullcycle.mjs +33 -17
- package/hub/gemini-adapter.mjs +69 -94
- package/hub/hitl.mjs +89 -30
- package/hub/intent.mjs +161 -38
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/mcp-response-cache.mjs +66 -32
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +35 -37
- package/hub/lib/process-utils.mjs +106 -37
- package/hub/lib/spawn-trace.mjs +527 -0
- package/hub/lib/ssh-command.mjs +34 -4
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +57 -48
- package/hub/promote-penalties.mjs +25 -7
- package/hub/quality/deslop.mjs +70 -49
- package/hub/research.mjs +32 -25
- package/hub/router.mjs +240 -107
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +76 -28
- package/hub/server.mjs +4 -4
- package/hub/session-fingerprint.mjs +126 -60
- package/hub/state.mjs +84 -43
- package/hub/store-adapter.mjs +59 -26
- package/hub/store.mjs +356 -153
- package/hub/team/agent-map.json +22 -7
- package/hub/team/ansi.mjs +186 -122
- package/hub/team/backend.mjs +28 -10
- package/hub/team/cli/commands/attach.mjs +29 -9
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +32 -11
- package/hub/team/cli/commands/focus.mjs +38 -11
- package/hub/team/cli/commands/interrupt.mjs +18 -6
- package/hub/team/cli/commands/kill.mjs +16 -5
- package/hub/team/cli/commands/list.mjs +11 -4
- package/hub/team/cli/commands/send.mjs +19 -6
- package/hub/team/cli/commands/start/index.mjs +154 -31
- package/hub/team/cli/commands/start/parse-args.mjs +38 -11
- package/hub/team/cli/commands/start/start-headless.mjs +112 -36
- package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
- package/hub/team/cli/commands/start/start-mux.mjs +70 -21
- package/hub/team/cli/commands/start/start-wt.mjs +29 -12
- package/hub/team/cli/commands/status.mjs +43 -14
- package/hub/team/cli/commands/stop.mjs +11 -4
- package/hub/team/cli/commands/task.mjs +8 -3
- package/hub/team/cli/commands/tasks.mjs +1 -1
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +30 -8
- package/hub/team/cli/services/attach-fallback.mjs +31 -11
- package/hub/team/cli/services/hub-client.mjs +42 -14
- package/hub/team/cli/services/member-selector.mjs +11 -4
- package/hub/team/cli/services/native-control.mjs +48 -21
- package/hub/team/cli/services/runtime-mode.mjs +2 -1
- package/hub/team/cli/services/state-store.mjs +25 -8
- package/hub/team/cli/services/task-model.mjs +16 -6
- package/hub/team/conductor-mesh-bridge.mjs +24 -23
- package/hub/team/conductor.mjs +8 -4
- package/hub/team/dashboard-anchor.mjs +4 -5
- package/hub/team/dashboard-layout.mjs +3 -1
- package/hub/team/dashboard-open.mjs +41 -21
- package/hub/team/dashboard.mjs +76 -28
- package/hub/team/event-log.mjs +18 -10
- package/hub/team/handoff.mjs +31 -15
- package/hub/team/headless.mjs +2 -1
- package/hub/team/health-probe.mjs +69 -54
- package/hub/team/launcher-template.mjs +16 -13
- package/hub/team/native-supervisor.mjs +65 -21
- package/hub/team/native.mjs +74 -35
- package/hub/team/nativeProxy.mjs +184 -113
- package/hub/team/notify.mjs +119 -76
- package/hub/team/orchestrator.mjs +9 -4
- package/hub/team/pane.mjs +12 -7
- package/hub/team/process-cleanup.mjs +25 -16
- package/hub/team/psmux.mjs +491 -201
- package/hub/team/remote-probe.mjs +68 -52
- package/hub/team/remote-session.mjs +117 -59
- package/hub/team/remote-watcher.mjs +61 -33
- package/hub/team/routing.mjs +51 -25
- package/hub/team/runtime-strategy.mjs +3 -1
- package/hub/team/session.mjs +98 -34
- package/hub/team/staleState.mjs +72 -30
- package/hub/team/swarm-locks.mjs +15 -13
- package/hub/team/swarm-planner.mjs +32 -21
- package/hub/team/swarm-reconciler.mjs +48 -23
- package/hub/team/tui-lite.mjs +266 -68
- package/hub/team/tui-remote-adapter.mjs +14 -10
- package/hub/team/tui-viewer.mjs +99 -43
- package/hub/team/tui.mjs +708 -271
- package/hub/team/worktree-lifecycle.mjs +152 -58
- package/hub/team/wt-manager.mjs +24 -14
- package/hub/token-mode.mjs +71 -71
- package/hub/tray.mjs +66 -23
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-mcp.mjs +192 -141
- package/hub/workers/delegator-mcp.mjs +507 -333
- package/hub/workers/factory.mjs +8 -8
- package/hub/workers/gemini-worker.mjs +115 -84
- package/hub/workers/interface.mjs +6 -1
- package/hub/workers/worker-utils.mjs +21 -14
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +162 -26
- package/hud/context-monitor.mjs +82 -41
- package/hud/hud-qos-status.mjs +129 -49
- package/hud/mission-board.mjs +6 -3
- package/hud/providers/claude.mjs +226 -115
- package/hud/providers/codex.mjs +62 -22
- package/hud/providers/gemini.mjs +168 -56
- package/hud/renderers.mjs +384 -119
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +78 -38
- package/mesh/index.mjs +11 -5
- package/mesh/mesh-budget.mjs +18 -9
- package/mesh/mesh-heartbeat.mjs +1 -1
- package/mesh/mesh-queue.mjs +3 -5
- package/mesh/mesh-router.mjs +5 -4
- package/package.json +2 -1
- package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
- package/scripts/__tests__/keyword-detector.test.mjs +77 -28
- package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
- package/scripts/__tests__/remote-spawn.test.mjs +10 -4
- package/scripts/__tests__/session-start-fast.test.mjs +36 -0
- package/scripts/__tests__/skill-template.test.mjs +98 -50
- package/scripts/__tests__/smoke.test.mjs +1 -1
- package/scripts/__tests__/spawn-trace.test.mjs +102 -0
- package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
- package/scripts/cache-doctor.mjs +11 -4
- package/scripts/cache-warmup.mjs +96 -37
- package/scripts/claudemd-sync.mjs +27 -17
- package/scripts/codex-gateway-preflight.mjs +52 -37
- package/scripts/codex-mcp-gateway-sync.mjs +59 -39
- package/scripts/completions/tfx.bash +47 -47
- package/scripts/completions/tfx.fish +44 -44
- package/scripts/completions/tfx.zsh +83 -83
- package/scripts/config-audit.mjs +232 -0
- package/scripts/convert-to-tmpl.mjs +54 -0
- package/scripts/cross-review-gate.mjs +35 -12
- package/scripts/cross-review-tracker.mjs +21 -8
- package/scripts/demo.mjs +35 -17
- package/scripts/doctor-diagnose.mjs +284 -0
- package/scripts/gen-skill-docs.mjs +7 -2
- package/scripts/gen-skill-manifest.mjs +2 -1
- package/scripts/headless-guard.mjs +86 -48
- package/scripts/hub-ensure.mjs +45 -26
- package/scripts/keyword-detector.mjs +41 -20
- package/scripts/keyword-rules-expander.mjs +47 -30
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +6 -3
- package/scripts/lib/env-probe.mjs +47 -28
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/keyword-rules.mjs +43 -19
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +377 -239
- package/scripts/lib/mcp-guard-engine.mjs +194 -79
- package/scripts/lib/mcp-manifest.mjs +23 -13
- package/scripts/lib/mcp-server-catalog.mjs +300 -63
- package/scripts/lib/psmux-info.mjs +11 -6
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-template.mjs +30 -7
- package/scripts/mcp-check.mjs +58 -39
- package/scripts/mcp-gateway-config.mjs +83 -39
- package/scripts/mcp-gateway-ensure.mjs +43 -35
- package/scripts/mcp-gateway-integration-test.mjs +70 -58
- package/scripts/mcp-gateway-start.mjs +126 -60
- package/scripts/mcp-gateway-verify.mjs +24 -22
- package/scripts/mcp-safety-guard.mjs +44 -11
- package/scripts/notion-read.mjs +199 -84
- package/scripts/pack.mjs +94 -89
- package/scripts/preflight-cache.mjs +27 -10
- package/scripts/preinstall.mjs +42 -13
- package/scripts/remote-spawn.mjs +309 -94
- package/scripts/run.cjs +8 -5
- package/scripts/session-spawn-helper.mjs +130 -39
- package/scripts/session-stale-cleanup.mjs +123 -0
- package/scripts/setup.mjs +941 -492
- package/scripts/test-lock.mjs +20 -7
- package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
- package/scripts/tfx-batch-stats.mjs +32 -11
- package/scripts/tfx-gate-activate.mjs +11 -4
- package/scripts/tfx-route-post.mjs +87 -20
- package/scripts/tfx-route-worker.mjs +57 -51
- package/scripts/tfx-route.sh +41 -124
- package/scripts/tmp-cleanup.mjs +21 -7
- package/scripts/token-snapshot.mjs +204 -85
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
- package/skills/.omc/state/idle-notif-cooldown.json +3 -0
- package/skills/.omc/state/last-tool-error.json +7 -0
- package/skills/.omc/state/subagent-tracking.json +7 -0
- package/skills/_templates/base.md +1 -6
- package/skills/merge-worktree/SKILL.md.tmpl +144 -0
- package/skills/shared/telemetry-segment.md +6 -0
- package/skills/star-prompt/SKILL.md.tmpl +222 -0
- package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
- package/skills/tfx-analysis/skill.json +1 -6
- package/skills/tfx-auto/SKILL.md +1 -0
- package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
- package/skills/tfx-auto-codex/skill.json +1 -3
- package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
- package/skills/tfx-autopilot/skill.json +1 -5
- package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
- package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
- package/skills/tfx-autoroute/skill.json +1 -7
- package/skills/tfx-codex/SKILL.md +1 -0
- package/skills/tfx-codex/skill.json +1 -3
- package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
- package/skills/tfx-codex-swarm/evals/evals.json +1 -1
- package/skills/tfx-codex-swarm/skill.json +1 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
- package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
- package/skills/tfx-debate/SKILL.md.tmpl +192 -0
- package/skills/tfx-debate/skill.json +1 -7
- package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
- package/skills/tfx-deep-analysis/skill.json +1 -5
- package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
- package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
- package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
- package/skills/tfx-deep-qa/skill.json +1 -6
- package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
- package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
- package/skills/tfx-doctor/SKILL.md +21 -0
- package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
- package/skills/tfx-doctor/skill.json +1 -3
- package/skills/tfx-find/SKILL.md +1 -0
- package/skills/tfx-forge/SKILL.md.tmpl +187 -0
- package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
- package/skills/tfx-fullcycle/skill.json +1 -6
- package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
- package/skills/tfx-gemini/skill.json +1 -3
- package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
- package/skills/tfx-hooks/skill.json +1 -3
- package/skills/tfx-hub/SKILL.md.tmpl +212 -0
- package/skills/tfx-hub/skill.json +1 -3
- package/skills/tfx-index/SKILL.md +1 -0
- package/skills/tfx-index/skill.json +1 -6
- package/skills/tfx-interview/SKILL.md.tmpl +285 -0
- package/skills/tfx-multi/SKILL.md.tmpl +183 -0
- package/skills/tfx-multi/skill.json +1 -3
- package/skills/tfx-panel/SKILL.md.tmpl +189 -0
- package/skills/tfx-panel/skill.json +1 -7
- package/skills/tfx-persist/SKILL.md.tmpl +270 -0
- package/skills/tfx-persist/skill.json +1 -7
- package/skills/tfx-plan/SKILL.md +1 -0
- package/skills/tfx-plan/skill.json +1 -6
- package/skills/tfx-profile/SKILL.md.tmpl +239 -0
- package/skills/tfx-profile/skill.json +1 -3
- package/skills/tfx-prune/SKILL.md.tmpl +200 -0
- package/skills/tfx-prune/skill.json +1 -7
- package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
- package/skills/tfx-psmux-rules/skill.json +1 -4
- package/skills/tfx-qa/SKILL.md +1 -0
- package/skills/tfx-qa/skill.json +1 -6
- package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
- package/skills/tfx-ralph/skill.json +1 -4
- package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
- package/skills/tfx-remote-setup/skill.json +1 -3
- package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
- package/skills/tfx-remote-spawn/references/hosts.json +16 -0
- package/skills/tfx-remote-spawn/skill.json +1 -4
- package/skills/tfx-research/SKILL.md +1 -0
- package/skills/tfx-review/SKILL.md +1 -0
- package/skills/tfx-review/skill.json +1 -6
- package/skills/tfx-setup/SKILL.md.tmpl +504 -0
- package/skills/tfx-setup/skill.json +1 -3
- package/skills/tfx-swarm/SKILL.md +22 -0
- package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
- package/tui/codex-profile.mjs +88 -33
- package/tui/core.mjs +45 -15
- package/tui/doctor.mjs +75 -28
- package/tui/gemini-profile.mjs +74 -29
- package/tui/monitor-data.mjs +8 -4
- package/tui/monitor.mjs +71 -27
- package/tui/setup.mjs +133 -42
package/hub/team/tui-lite.mjs
CHANGED
|
@@ -1,10 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
altScreenOff,
|
|
3
|
+
altScreenOn,
|
|
4
|
+
BG,
|
|
5
|
+
bold,
|
|
6
|
+
box,
|
|
7
|
+
clearScreen,
|
|
8
|
+
clearToEnd,
|
|
9
|
+
color,
|
|
10
|
+
cursorHide,
|
|
11
|
+
cursorHome,
|
|
12
|
+
cursorShow,
|
|
13
|
+
dim,
|
|
14
|
+
eraseBelow,
|
|
15
|
+
FG,
|
|
16
|
+
MOCHA,
|
|
17
|
+
moveTo,
|
|
18
|
+
padRight,
|
|
19
|
+
progressBar,
|
|
20
|
+
statusBadge,
|
|
21
|
+
stripAnsi,
|
|
22
|
+
truncate,
|
|
23
|
+
wcswidth,
|
|
24
|
+
} from "./ansi.mjs";
|
|
2
25
|
|
|
3
|
-
const FALLBACK_COLUMNS = 100,
|
|
26
|
+
const FALLBACK_COLUMNS = 100,
|
|
27
|
+
FALLBACK_ROWS = 24;
|
|
4
28
|
const VALID_TABS = new Set(["log", "detail", "files"]);
|
|
5
29
|
|
|
6
30
|
let VERSION = "lite";
|
|
7
|
-
try {
|
|
31
|
+
try {
|
|
32
|
+
const { createRequire } = await import("node:module");
|
|
33
|
+
VERSION = createRequire(import.meta.url)("../../package.json").version;
|
|
34
|
+
} catch {}
|
|
8
35
|
|
|
9
36
|
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
10
37
|
|
|
@@ -76,39 +103,87 @@ function wrap(text, width) {
|
|
|
76
103
|
return lines;
|
|
77
104
|
}
|
|
78
105
|
|
|
79
|
-
const runtimeStatus = (worker) =>
|
|
106
|
+
const runtimeStatus = (worker) =>
|
|
107
|
+
worker?.handoff?.status || worker?.status || "pending";
|
|
80
108
|
|
|
81
109
|
function normalizeWorkerState(existing = {}, state = {}) {
|
|
82
|
-
const handoff =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
110
|
+
const handoff =
|
|
111
|
+
state.handoff === undefined
|
|
112
|
+
? existing.handoff
|
|
113
|
+
: {
|
|
114
|
+
...(existing.handoff || {}),
|
|
115
|
+
...(state.handoff || {}),
|
|
116
|
+
verdict:
|
|
117
|
+
state.handoff?.verdict !== undefined
|
|
118
|
+
? sanitizeOneLine(state.handoff.verdict)
|
|
119
|
+
: existing.handoff?.verdict,
|
|
120
|
+
confidence:
|
|
121
|
+
state.handoff?.confidence !== undefined
|
|
122
|
+
? sanitizeOneLine(state.handoff.confidence)
|
|
123
|
+
: existing.handoff?.confidence,
|
|
124
|
+
status:
|
|
125
|
+
state.handoff?.status !== undefined
|
|
126
|
+
? sanitizeOneLine(state.handoff.status)
|
|
127
|
+
: existing.handoff?.status,
|
|
128
|
+
files_changed:
|
|
129
|
+
state.handoff?.files_changed !== undefined
|
|
130
|
+
? sanitizeFiles(state.handoff.files_changed)
|
|
131
|
+
: existing.handoff?.files_changed,
|
|
132
|
+
};
|
|
92
133
|
return {
|
|
93
134
|
...existing,
|
|
94
135
|
...state,
|
|
95
|
-
cli:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
136
|
+
cli:
|
|
137
|
+
state.cli !== undefined
|
|
138
|
+
? sanitizeOneLine(state.cli, existing.cli || "codex")
|
|
139
|
+
: existing.cli || "codex",
|
|
140
|
+
status:
|
|
141
|
+
state.status !== undefined
|
|
142
|
+
? sanitizeOneLine(state.status, existing.status || "pending")
|
|
143
|
+
: existing.status || "pending",
|
|
144
|
+
snapshot:
|
|
145
|
+
state.snapshot !== undefined
|
|
146
|
+
? sanitizeBlock(state.snapshot)
|
|
147
|
+
: existing.snapshot,
|
|
148
|
+
summary:
|
|
149
|
+
state.summary !== undefined
|
|
150
|
+
? sanitizeBlock(state.summary)
|
|
151
|
+
: existing.summary,
|
|
152
|
+
detail:
|
|
153
|
+
state.detail !== undefined
|
|
154
|
+
? sanitizeBlock(state.detail)
|
|
155
|
+
: existing.detail,
|
|
156
|
+
findings:
|
|
157
|
+
state.findings !== undefined
|
|
158
|
+
? sanitizeFiles(state.findings)
|
|
159
|
+
: existing.findings,
|
|
160
|
+
files_changed:
|
|
161
|
+
state.files_changed !== undefined
|
|
162
|
+
? sanitizeFiles(state.files_changed)
|
|
163
|
+
: existing.files_changed,
|
|
164
|
+
confidence:
|
|
165
|
+
state.confidence !== undefined
|
|
166
|
+
? sanitizeOneLine(state.confidence)
|
|
167
|
+
: existing.confidence,
|
|
168
|
+
tokens:
|
|
169
|
+
state.tokens !== undefined
|
|
170
|
+
? normalizeTokens(state.tokens)
|
|
171
|
+
: existing.tokens,
|
|
172
|
+
progress:
|
|
173
|
+
state.progress !== undefined
|
|
174
|
+
? clamp(Number(state.progress) || 0, 0, 1)
|
|
175
|
+
: existing.progress,
|
|
105
176
|
handoff,
|
|
106
177
|
};
|
|
107
178
|
}
|
|
108
179
|
|
|
109
180
|
function frame(lines, width, border = MOCHA.border) {
|
|
110
181
|
const body = lines.length ? lines : [dim("내용 없음")];
|
|
111
|
-
const rendered = box(
|
|
182
|
+
const rendered = box(
|
|
183
|
+
body.map((line) => padRight(truncate(line, width - 4), width - 4)),
|
|
184
|
+
width,
|
|
185
|
+
border,
|
|
186
|
+
);
|
|
112
187
|
return [rendered.top, ...rendered.body, rendered.bot];
|
|
113
188
|
}
|
|
114
189
|
|
|
@@ -128,9 +203,10 @@ function buildHeader(width, names, workers, pipeline, startedAt) {
|
|
|
128
203
|
else if (status === "running" || status === "in_progress") counts.running++;
|
|
129
204
|
}
|
|
130
205
|
const elapsed = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
|
|
131
|
-
const line1 =
|
|
132
|
-
|
|
133
|
-
|
|
206
|
+
const line1 =
|
|
207
|
+
color(` triflux ${VERSION} `, FG.white, BG.header) +
|
|
208
|
+
` ${bold(`phase ${pipeline.phase || "exec"}`)}` +
|
|
209
|
+
` ${dim(`+${elapsed}s`)} ${names.length} workers`;
|
|
134
210
|
const line2 = `${color(`ok ${counts.ok}`, MOCHA.ok)} ${color(`partial ${counts.partial}`, MOCHA.partial)} ${color(`failed ${counts.failed}`, MOCHA.fail)} ${color(`running ${counts.running}`, MOCHA.executing)}`;
|
|
135
211
|
return [padRight(line1, width), padRight(line2, width)];
|
|
136
212
|
}
|
|
@@ -140,9 +216,14 @@ function buildWorkerRail(names, workers, selectedWorker, width) {
|
|
|
140
216
|
? names.map((name, index) => {
|
|
141
217
|
const worker = workers.get(name);
|
|
142
218
|
const status = runtimeStatus(worker);
|
|
143
|
-
const pct = Math.round(
|
|
144
|
-
|
|
145
|
-
|
|
219
|
+
const pct = Math.round(
|
|
220
|
+
((worker?.progress ?? (status === "completed" ? 1 : 0)) || 0) * 100,
|
|
221
|
+
);
|
|
222
|
+
const token = worker?.tokens
|
|
223
|
+
? ` tok ${formatTokens(worker.tokens)}`
|
|
224
|
+
: "";
|
|
225
|
+
const prefix =
|
|
226
|
+
name === selectedWorker ? color("▶", MOCHA.blue) : dim("·");
|
|
146
227
|
return `${prefix} ${index + 1}.${name} ${stripAnsi(statusBadge(status))} ${pct}%${token}`;
|
|
147
228
|
})
|
|
148
229
|
: [dim("workers 없음")];
|
|
@@ -175,12 +256,27 @@ function buildDetail(workerName, worker, width, tab, helpVisible) {
|
|
|
175
256
|
`verdict ${worker.handoff?.verdict || worker.summary || worker.snapshot || "-"}`,
|
|
176
257
|
];
|
|
177
258
|
if (tab === "files") {
|
|
178
|
-
const files = [
|
|
179
|
-
|
|
259
|
+
const files = [
|
|
260
|
+
...sanitizeFiles(worker.handoff?.files_changed),
|
|
261
|
+
...sanitizeFiles(worker.files_changed),
|
|
262
|
+
];
|
|
263
|
+
detailLines.push(
|
|
264
|
+
...(files.length ? files.map((file) => `files ${file}`) : ["files 없음"]),
|
|
265
|
+
);
|
|
180
266
|
} else if (tab === "detail") {
|
|
181
|
-
detailLines.push(
|
|
267
|
+
detailLines.push(
|
|
268
|
+
...wrap(
|
|
269
|
+
worker.detail || worker.summary || worker.snapshot || "",
|
|
270
|
+
width - 4,
|
|
271
|
+
),
|
|
272
|
+
);
|
|
182
273
|
} else {
|
|
183
|
-
detailLines.push(
|
|
274
|
+
detailLines.push(
|
|
275
|
+
...wrap(
|
|
276
|
+
worker.summary || worker.snapshot || worker.detail || "",
|
|
277
|
+
width - 4,
|
|
278
|
+
),
|
|
279
|
+
);
|
|
184
280
|
}
|
|
185
281
|
return frame(detailLines, width, MOCHA.thinking);
|
|
186
282
|
}
|
|
@@ -214,11 +310,21 @@ export function createLiteDashboard(opts = {}) {
|
|
|
214
310
|
let inputAttached = false;
|
|
215
311
|
let rawModeEnabled = false;
|
|
216
312
|
|
|
217
|
-
const write = (text) => {
|
|
313
|
+
const write = (text) => {
|
|
314
|
+
if (!closed) stream.write(text);
|
|
315
|
+
};
|
|
218
316
|
const workerNames = () => [...workers.keys()].sort();
|
|
219
|
-
const viewportColumns = () =>
|
|
220
|
-
|
|
221
|
-
|
|
317
|
+
const viewportColumns = () =>
|
|
318
|
+
Math.max(
|
|
319
|
+
48,
|
|
320
|
+
columns || stream?.columns || process.stdout?.columns || FALLBACK_COLUMNS,
|
|
321
|
+
);
|
|
322
|
+
const viewportRows = () =>
|
|
323
|
+
Math.max(10, rows || stream?.rows || process.stdout?.rows || FALLBACK_ROWS);
|
|
324
|
+
const ensureSelection = (names) => {
|
|
325
|
+
if (names.length && (!selectedWorker || !workers.has(selectedWorker)))
|
|
326
|
+
selectedWorker = names[0];
|
|
327
|
+
};
|
|
222
328
|
|
|
223
329
|
function selectRelative(offset) {
|
|
224
330
|
const names = workerNames();
|
|
@@ -229,9 +335,18 @@ export function createLiteDashboard(opts = {}) {
|
|
|
229
335
|
}
|
|
230
336
|
|
|
231
337
|
function triggerOpenSelected() {
|
|
232
|
-
if (
|
|
338
|
+
if (
|
|
339
|
+
typeof onOpenSelectedWorker !== "function" ||
|
|
340
|
+
!selectedWorker ||
|
|
341
|
+
!workers.has(selectedWorker)
|
|
342
|
+
)
|
|
343
|
+
return;
|
|
233
344
|
try {
|
|
234
|
-
const result = onOpenSelectedWorker(
|
|
345
|
+
const result = onOpenSelectedWorker(
|
|
346
|
+
selectedWorker,
|
|
347
|
+
workers.get(selectedWorker),
|
|
348
|
+
new Map(workers),
|
|
349
|
+
);
|
|
235
350
|
if (result && typeof result.catch === "function") result.catch(() => {});
|
|
236
351
|
} catch {}
|
|
237
352
|
}
|
|
@@ -239,7 +354,11 @@ export function createLiteDashboard(opts = {}) {
|
|
|
239
354
|
function triggerOpenAll() {
|
|
240
355
|
if (typeof onOpenAllWorkers !== "function") return;
|
|
241
356
|
try {
|
|
242
|
-
const result = onOpenAllWorkers(
|
|
357
|
+
const result = onOpenAllWorkers(
|
|
358
|
+
selectedWorker,
|
|
359
|
+
workers.get(selectedWorker),
|
|
360
|
+
new Map(workers),
|
|
361
|
+
);
|
|
243
362
|
if (result && typeof result.catch === "function") result.catch(() => {});
|
|
244
363
|
} catch {}
|
|
245
364
|
}
|
|
@@ -265,7 +384,11 @@ export function createLiteDashboard(opts = {}) {
|
|
|
265
384
|
return;
|
|
266
385
|
}
|
|
267
386
|
if (key === "\r" || key === "\n") {
|
|
268
|
-
if (
|
|
387
|
+
if (
|
|
388
|
+
typeof onOpenSelectedWorker === "function" &&
|
|
389
|
+
selectedWorker &&
|
|
390
|
+
workers.has(selectedWorker)
|
|
391
|
+
) {
|
|
269
392
|
triggerOpenSelected();
|
|
270
393
|
} else {
|
|
271
394
|
// 콜백 없거나 선택 워커 없으면 탭 순환
|
|
@@ -275,7 +398,12 @@ export function createLiteDashboard(opts = {}) {
|
|
|
275
398
|
render();
|
|
276
399
|
return;
|
|
277
400
|
}
|
|
278
|
-
if (
|
|
401
|
+
if (
|
|
402
|
+
key === "\x1b[13;2u" ||
|
|
403
|
+
key === "\x1b[27;13;2~" ||
|
|
404
|
+
key === "\x1b\r" ||
|
|
405
|
+
key === "\x1b\n"
|
|
406
|
+
) {
|
|
279
407
|
triggerOpenAll();
|
|
280
408
|
return;
|
|
281
409
|
}
|
|
@@ -322,20 +450,53 @@ export function createLiteDashboard(opts = {}) {
|
|
|
322
450
|
const width = viewportColumns();
|
|
323
451
|
const height = viewportRows();
|
|
324
452
|
const header = buildHeader(width, names, workers, pipeline, startedAt);
|
|
325
|
-
const railOnly =
|
|
453
|
+
const railOnly =
|
|
454
|
+
!detailExpanded ||
|
|
455
|
+
names.length <= 1 ||
|
|
456
|
+
width < 100 ||
|
|
457
|
+
layout === "single";
|
|
326
458
|
if (railOnly) {
|
|
327
|
-
const sections = [
|
|
328
|
-
|
|
459
|
+
const sections = [
|
|
460
|
+
header,
|
|
461
|
+
...buildWorkerRail(names, workers, selectedWorker, width),
|
|
462
|
+
];
|
|
463
|
+
if (detailExpanded)
|
|
464
|
+
sections.push(
|
|
465
|
+
...buildDetail(
|
|
466
|
+
selectedWorker,
|
|
467
|
+
workers.get(selectedWorker),
|
|
468
|
+
width,
|
|
469
|
+
focusTab,
|
|
470
|
+
helpVisible,
|
|
471
|
+
),
|
|
472
|
+
);
|
|
329
473
|
return fitHeight(sections, width, height);
|
|
330
474
|
}
|
|
331
475
|
const railWidth = Math.max(28, Math.floor(width * 0.32));
|
|
332
476
|
const detailWidth = width - railWidth - 1;
|
|
333
477
|
const bodyHeight = Math.max(6, height - header.length);
|
|
334
|
-
const rail = fitHeight(
|
|
335
|
-
|
|
478
|
+
const rail = fitHeight(
|
|
479
|
+
buildWorkerRail(names, workers, selectedWorker, railWidth),
|
|
480
|
+
railWidth,
|
|
481
|
+
bodyHeight,
|
|
482
|
+
);
|
|
483
|
+
const detail = fitHeight(
|
|
484
|
+
buildDetail(
|
|
485
|
+
selectedWorker,
|
|
486
|
+
workers.get(selectedWorker),
|
|
487
|
+
detailWidth,
|
|
488
|
+
focusTab,
|
|
489
|
+
helpVisible,
|
|
490
|
+
),
|
|
491
|
+
detailWidth,
|
|
492
|
+
bodyHeight,
|
|
493
|
+
);
|
|
336
494
|
return [
|
|
337
495
|
...header,
|
|
338
|
-
...Array.from(
|
|
496
|
+
...Array.from(
|
|
497
|
+
{ length: bodyHeight },
|
|
498
|
+
(_, index) => `${rail[index]}${dim("│")}${detail[index]}`,
|
|
499
|
+
),
|
|
339
500
|
];
|
|
340
501
|
}
|
|
341
502
|
|
|
@@ -350,7 +511,11 @@ export function createLiteDashboard(opts = {}) {
|
|
|
350
511
|
// Full redraw on first frame or terminal resize to avoid artifacts
|
|
351
512
|
if (prevFrame.length === 0 || width !== prevWidth) {
|
|
352
513
|
prevWidth = width;
|
|
353
|
-
write(
|
|
514
|
+
write(
|
|
515
|
+
cursorHome +
|
|
516
|
+
padded.map((l) => l + clearToEnd).join("\n") +
|
|
517
|
+
eraseBelow,
|
|
518
|
+
);
|
|
354
519
|
prevFrame = padded;
|
|
355
520
|
return;
|
|
356
521
|
}
|
|
@@ -372,8 +537,10 @@ export function createLiteDashboard(opts = {}) {
|
|
|
372
537
|
function close() {
|
|
373
538
|
if (closed) return;
|
|
374
539
|
if (timer) clearInterval(timer);
|
|
375
|
-
if (inputAttached && typeof input?.off === "function")
|
|
376
|
-
|
|
540
|
+
if (inputAttached && typeof input?.off === "function")
|
|
541
|
+
input.off("data", handleInput);
|
|
542
|
+
if (rawModeEnabled && typeof input?.setRawMode === "function")
|
|
543
|
+
input.setRawMode(false);
|
|
377
544
|
if (inputAttached && typeof input?.pause === "function") input.pause();
|
|
378
545
|
if (isTTY) write(cursorShow + altScreenOff);
|
|
379
546
|
prevFrame = [];
|
|
@@ -387,22 +554,53 @@ export function createLiteDashboard(opts = {}) {
|
|
|
387
554
|
}
|
|
388
555
|
|
|
389
556
|
return {
|
|
390
|
-
updateWorker(name, state) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
557
|
+
updateWorker(name, state) {
|
|
558
|
+
workers.set(name, normalizeWorkerState(workers.get(name), state));
|
|
559
|
+
ensureSelection(workerNames());
|
|
560
|
+
},
|
|
561
|
+
updatePipeline(state) {
|
|
562
|
+
pipeline = { ...pipeline, ...state };
|
|
563
|
+
},
|
|
564
|
+
setStartTime(ms) {
|
|
565
|
+
startedAt = ms;
|
|
566
|
+
},
|
|
567
|
+
selectWorker(name) {
|
|
568
|
+
if (workers.has(name)) selectedWorker = name;
|
|
569
|
+
},
|
|
570
|
+
toggleDetail(force) {
|
|
571
|
+
detailExpanded = typeof force === "boolean" ? force : !detailExpanded;
|
|
572
|
+
},
|
|
395
573
|
render,
|
|
396
|
-
getWorkers() {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
574
|
+
getWorkers() {
|
|
575
|
+
return new Map(workers);
|
|
576
|
+
},
|
|
577
|
+
getFrameCount() {
|
|
578
|
+
return frameCount;
|
|
579
|
+
},
|
|
580
|
+
getPipelineState() {
|
|
581
|
+
return { ...pipeline };
|
|
582
|
+
},
|
|
583
|
+
getSelectedWorker() {
|
|
584
|
+
return selectedWorker;
|
|
585
|
+
},
|
|
586
|
+
isDetailExpanded() {
|
|
587
|
+
return detailExpanded;
|
|
588
|
+
},
|
|
589
|
+
getFocusTab() {
|
|
590
|
+
return focusTab;
|
|
591
|
+
},
|
|
592
|
+
setFocusTab(tab) {
|
|
593
|
+
if (VALID_TABS.has(tab)) focusTab = tab;
|
|
594
|
+
},
|
|
595
|
+
getLayout() {
|
|
596
|
+
return layout;
|
|
597
|
+
},
|
|
598
|
+
toggleHelp(force) {
|
|
599
|
+
helpVisible = typeof force === "boolean" ? force : !helpVisible;
|
|
600
|
+
},
|
|
601
|
+
isHelpVisible() {
|
|
602
|
+
return helpVisible;
|
|
603
|
+
},
|
|
406
604
|
close,
|
|
407
605
|
};
|
|
408
606
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
// tui.mjs updateWorker() 호환 형식으로 변환한다.
|
|
5
5
|
// 완료/실패 시 notify.mjs 자동 호출.
|
|
6
6
|
|
|
7
|
+
import { EventEmitter } from "node:events";
|
|
7
8
|
import { readFileSync } from "node:fs";
|
|
8
9
|
import { join } from "node:path";
|
|
9
10
|
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { EventEmitter } from "node:events";
|
|
11
11
|
|
|
12
12
|
import { STATES } from "./conductor.mjs";
|
|
13
13
|
|
|
@@ -90,9 +90,8 @@ function mapConductorStateToStatus(conductorState) {
|
|
|
90
90
|
function buildWorkerData(entry, watcherSession, hostsData) {
|
|
91
91
|
const host = entry.host || resolveHostFromSessionName(entry.id);
|
|
92
92
|
const snapshot = watcherSession?.lastOutput || "";
|
|
93
|
-
const probeLevel =
|
|
94
|
-
|| watcherSession?.lastProbeLevel
|
|
95
|
-
|| null;
|
|
93
|
+
const probeLevel =
|
|
94
|
+
entry.health?.level || watcherSession?.lastProbeLevel || null;
|
|
96
95
|
|
|
97
96
|
return Object.freeze({
|
|
98
97
|
cli: entry.agent || "claude",
|
|
@@ -115,15 +114,18 @@ function buildWorkerData(entry, watcherSession, hostsData) {
|
|
|
115
114
|
* remote-watcher 전용 엔트리 → TUI 워커 데이터 (conductor 미등록 세션).
|
|
116
115
|
*/
|
|
117
116
|
function buildWatcherOnlyWorkerData(watcherRecord, hostsData) {
|
|
118
|
-
const host =
|
|
119
|
-
|| resolveHostFromSessionName(watcherRecord.sessionName);
|
|
117
|
+
const host =
|
|
118
|
+
watcherRecord.host || resolveHostFromSessionName(watcherRecord.sessionName);
|
|
120
119
|
|
|
121
120
|
return Object.freeze({
|
|
122
121
|
cli: "claude",
|
|
123
122
|
role: resolveRole(null, watcherRecord.sessionName),
|
|
124
|
-
status:
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
status:
|
|
124
|
+
watcherRecord.state === "completed"
|
|
125
|
+
? "completed"
|
|
126
|
+
: watcherRecord.state === "failed"
|
|
127
|
+
? "failed"
|
|
128
|
+
: "running",
|
|
127
129
|
host: host || "unknown",
|
|
128
130
|
remote: true,
|
|
129
131
|
sshUser: resolveSshUser(hostsData, host),
|
|
@@ -321,7 +323,9 @@ export function createRemoteAdapter(opts = {}) {
|
|
|
321
323
|
// watcher-only 세션 (conductor 미등록)
|
|
322
324
|
if (watcher) {
|
|
323
325
|
const watcherStatus = watcher.getStatus();
|
|
324
|
-
for (const [sessionName, record] of Object.entries(
|
|
326
|
+
for (const [sessionName, record] of Object.entries(
|
|
327
|
+
watcherStatus.sessions || {},
|
|
328
|
+
)) {
|
|
325
329
|
if (conductorSessionIds.has(sessionName)) continue;
|
|
326
330
|
const paneName = buildPaneName(sessionName);
|
|
327
331
|
const workerData = buildWatcherOnlyWorkerData(record, hostsData);
|