triflux 8.11.2 → 8.12.2
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/.claude-plugin/plugin.json +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/hooks/hooks.json +56 -51
- package/hub/pipeline/index.mjs +318 -318
- package/hub/routing/q-learning.mjs +2 -1
- package/hub/schema.sql +146 -146
- package/hub/team/cli/commands/kill.mjs +37 -37
- package/hub/team/cli/commands/start/index.mjs +3 -2
- package/hub/team/cli/commands/start/parse-args.mjs +5 -0
- package/hub/team/cli/commands/start/start-headless.mjs +2 -1
- package/hub/team/cli/commands/stop.mjs +31 -31
- package/hub/team/cli/commands/task.mjs +30 -30
- package/hub/team/cli/help.mjs +41 -40
- package/hub/team/cli/services/hub-client.mjs +208 -208
- package/hub/team/cli/services/native-control.mjs +118 -118
- package/hub/team/cli/services/runtime-mode.mjs +62 -62
- package/hub/team/cli/services/state-store.mjs +48 -48
- package/hub/team/dashboard-anchor.mjs +14 -0
- package/hub/team/dashboard.mjs +274 -274
- package/hub/team/headless.mjs +44 -19
- package/hub/team/native.mjs +649 -649
- package/hub/tools.mjs +554 -554
- package/hub/workers/delegator-mcp.mjs +21 -1
- package/package.json +1 -1
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +117 -0
- package/scripts/__tests__/remote-spawn.test.mjs +78 -0
- package/scripts/cache-buildup.mjs +401 -0
- package/scripts/headless-guard.mjs +10 -3
- package/scripts/hub-ensure.mjs +120 -120
- package/scripts/lib/mcp-filter.mjs +720 -720
- package/scripts/lib/remote-spawn-transfer.mjs +196 -0
- package/scripts/mcp-check.mjs +237 -127
- package/scripts/mcp-gateway-ensure.mjs +6 -8
- package/scripts/mcp-gateway-integration-test.mjs +228 -0
- package/scripts/mcp-gateway-start.mjs +42 -16
- package/scripts/mcp-gateway-start.ps1 +17 -14
- package/scripts/mcp-gateway-verify.mjs +1 -1
- package/scripts/preflight-cache.mjs +137 -137
- package/scripts/remote-spawn.mjs +404 -40
- package/scripts/setup.mjs +18 -0
- package/scripts/tfx-route-worker.mjs +165 -165
- package/scripts/tfx-route.sh +85 -16
- package/scripts/token-snapshot.mjs +575 -575
- package/skills/tfx-analysis/SKILL.md +101 -101
- package/skills/tfx-autopilot/SKILL.md +112 -112
- package/skills/tfx-autoresearch/SKILL.md +1 -0
- package/skills/tfx-autoroute/SKILL.md +184 -184
- package/skills/tfx-codex-swarm/SKILL.md +449 -0
- package/skills/tfx-codex-swarm/evals/evals.json +26 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +33 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +42 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +11 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +87 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +35 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +275 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +56 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +11 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +92 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +71 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +264 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +113 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +32 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +9 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +96 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +38 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +151 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +51 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +9 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +127 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +57 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +129 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +84 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +27 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +8 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +98 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +65 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +123 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +66 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +5 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +8 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +88 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +40 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +130 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +61 -0
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +5 -0
- package/skills/tfx-profile/SKILL.md +141 -51
- package/skills/tfx-qa/SKILL.md +117 -117
- package/skills/tfx-remote-spawn/references/hosts.json +16 -16
- package/skills/tfx-review/SKILL.md +51 -51
- package/skills/tfx-setup/SKILL.md +20 -0
- package/tui/gemini-profile.mjs +254 -0
- package/tui/setup.mjs +36 -1
- package/scripts/claude-logged.ps1 +0 -54
- package/scripts/demo-tui.mjs +0 -59
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +0 -1
- package/skills/.omc/state/idle-notif-cooldown.json +0 -3
- package/skills/.omc/state/last-tool-error.json +0 -7
- package/skills/.omc/state/subagent-tracking.json +0 -7
package/hub/team/headless.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { HANDOFF_INSTRUCTION_SHORT, processHandoff } from "./handoff.mjs";
|
|
23
23
|
import { getBackend } from "./backend.mjs";
|
|
24
24
|
import { resolveDashboardLayout } from "./dashboard-layout.mjs";
|
|
25
|
+
import { normalizeDashboardAnchor } from "./dashboard-anchor.mjs";
|
|
25
26
|
import { createLogDashboard } from "./tui.mjs";
|
|
26
27
|
|
|
27
28
|
const RESULT_DIR = join(tmpdir(), "tfx-headless");
|
|
@@ -49,6 +50,11 @@ export function resolveCliType(agentOrCli) {
|
|
|
49
50
|
return AGENT_TO_CLI[agentOrCli] || agentOrCli;
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
// remote-spawn.mjs의 escapePwshSingleQuoted와 동일 — 순환 의존 방지를 위해 인라인
|
|
54
|
+
function escapePwshSingleQuoted(value) {
|
|
55
|
+
return String(value).replace(/'/g, "''");
|
|
56
|
+
}
|
|
57
|
+
|
|
52
58
|
/** MCP 프로필별 프롬프트 힌트 (tfx-route.sh resolve_mcp_policy의 경량 미러) */
|
|
53
59
|
const MCP_PROFILE_HINTS = {
|
|
54
60
|
implement: "You have full filesystem read/write access. Implement changes directly.",
|
|
@@ -66,10 +72,11 @@ const MCP_PROFILE_HINTS = {
|
|
|
66
72
|
* @param {boolean} [opts.handoff=true]
|
|
67
73
|
* @param {string} [opts.mcp] — MCP 프로필 ("implement"|"analyze"|"review"|"docs")
|
|
68
74
|
* @param {string} [opts.contextFile] — 컨텍스트 파일 경로 (최대 32KB, UTF-8 안전 절단)
|
|
75
|
+
* @param {string} [opts.cwd] — 워커 실행 작업 디렉터리
|
|
69
76
|
* @returns {string} PowerShell 명령
|
|
70
77
|
*/
|
|
71
78
|
export function buildHeadlessCommand(cli, prompt, resultFile, opts = {}) {
|
|
72
|
-
const { handoff = true, mcp, contextFile, model } = opts;
|
|
79
|
+
const { handoff = true, mcp, contextFile, model, cwd } = opts;
|
|
73
80
|
const resolvedCli = resolveCliType(cli);
|
|
74
81
|
|
|
75
82
|
// contextFile 처리: 32KB(32768 bytes) 초과 시 UTF-8 안전 절단
|
|
@@ -96,7 +103,14 @@ export function buildHeadlessCommand(cli, prompt, resultFile, opts = {}) {
|
|
|
96
103
|
|
|
97
104
|
const backend = getBackend(resolvedCli);
|
|
98
105
|
const promptExpr = `(Get-Content -Raw '${promptFile}')`;
|
|
99
|
-
|
|
106
|
+
const backendCommand = backend.buildArgs(promptExpr, resultFile, { ...opts, model });
|
|
107
|
+
const safeCwd = typeof cwd === "string" ? cwd.trim().replace(/[\r\n\x00-\x1f]/g, "") : "";
|
|
108
|
+
if (safeCwd && (safeCwd.startsWith("\\\\") || safeCwd.startsWith("//"))) {
|
|
109
|
+
throw new Error("[headless] UNC 경로는 cwd로 사용할 수 없습니다: " + safeCwd);
|
|
110
|
+
}
|
|
111
|
+
if (!safeCwd) return backendCommand;
|
|
112
|
+
|
|
113
|
+
return `Set-Location -LiteralPath '${escapePwshSingleQuoted(safeCwd)}'; ${backendCommand}`;
|
|
100
114
|
}
|
|
101
115
|
|
|
102
116
|
/**
|
|
@@ -160,7 +174,7 @@ async function dispatchProgressive(sessionName, assignments, opts = {}) {
|
|
|
160
174
|
|
|
161
175
|
// 캡처 시작 + 컬러 배너 + 명령 dispatch
|
|
162
176
|
const resultFile = join(RESULT_DIR, `${sessionName}-${paneName}.txt`).replace(/\\/g, "/");
|
|
163
|
-
const cmd = buildHeadlessCommand(assignment.cli, assignment.prompt, resultFile, { mcp: assignment.mcp, model: assignment.model });
|
|
177
|
+
const cmd = buildHeadlessCommand(assignment.cli, assignment.prompt, resultFile, { mcp: assignment.mcp, model: assignment.model, cwd: assignment.cwd });
|
|
164
178
|
startCapture(sessionName, newPaneId);
|
|
165
179
|
// pane 간 pipe-pane EBUSY 방지 — 이벤트 루프 해방하며 순차 대기
|
|
166
180
|
if (i > 0) await new Promise(r => setTimeout(r, 300));
|
|
@@ -204,7 +218,7 @@ function dispatchBatch(sessionName, assignments, opts = {}) {
|
|
|
204
218
|
return assignments.map((assignment, i) => {
|
|
205
219
|
const paneName = `worker-${i + 1}`;
|
|
206
220
|
const resultFile = join(RESULT_DIR, `${sessionName}-${paneName}.txt`).replace(/\\/g, "/");
|
|
207
|
-
const cmd = buildHeadlessCommand(assignment.cli, assignment.prompt, resultFile, { mcp: assignment.mcp, model: assignment.model });
|
|
221
|
+
const cmd = buildHeadlessCommand(assignment.cli, assignment.prompt, resultFile, { mcp: assignment.mcp, model: assignment.model, cwd: assignment.cwd });
|
|
208
222
|
const scriptDir = join(RESULT_DIR, sessionName);
|
|
209
223
|
const dispatch = dispatchCommand(sessionName, paneName, cmd, { scriptDir, scriptName: paneName });
|
|
210
224
|
|
|
@@ -595,37 +609,45 @@ export function autoAttachTerminal(sessionName, opts = {}, workerCount = 2) {
|
|
|
595
609
|
"--", "psmux", "attach", "-t", sessionName,
|
|
596
610
|
], { detached: true, stdio: "ignore" });
|
|
597
611
|
child.unref();
|
|
598
|
-
|
|
612
|
+
// v7.2: mf up 제거 — 새 WT window/process로 attach하므로 포커스 이동 불필요
|
|
599
613
|
return true;
|
|
600
614
|
} catch { return false; }
|
|
601
615
|
}
|
|
602
616
|
|
|
617
|
+
export function buildDashboardAttachArgs(sessionName, dashboardLayout = "single", workerCount = 2, dashboardAnchor = "window") {
|
|
618
|
+
const safeName = String(sessionName).replace(/[^a-zA-Z0-9_\-]/g, "") || "tfx-session";
|
|
619
|
+
const resolvedDashboardLayout = resolveDashboardLayout(dashboardLayout, workerCount);
|
|
620
|
+
const resolvedDashboardAnchor = normalizeDashboardAnchor(dashboardAnchor);
|
|
621
|
+
const viewerPath = join(import.meta.dirname, "tui-viewer.mjs").replace(/\\/g, "/");
|
|
622
|
+
const viewerArgs = [
|
|
623
|
+
"--profile", "triflux",
|
|
624
|
+
"--title", `▲ ${safeName}`,
|
|
625
|
+
"--", "node", viewerPath, "--session", safeName, "--result-dir", RESULT_DIR, "--layout", resolvedDashboardLayout,
|
|
626
|
+
];
|
|
627
|
+
|
|
628
|
+
if (resolvedDashboardAnchor === "tab") {
|
|
629
|
+
return ["-w", "0", "nt", ...viewerArgs];
|
|
630
|
+
}
|
|
631
|
+
return ["-w", "new", ...viewerArgs];
|
|
632
|
+
}
|
|
633
|
+
|
|
603
634
|
/**
|
|
604
635
|
* v7.0: psmux 세션을 WT 탭에 attach (대시보드 + 워커 전체 뷰)
|
|
605
636
|
* @param {string} sessionName
|
|
606
637
|
* @param {number} workerCount
|
|
607
638
|
* @param {string} [dashboardLayout='single']
|
|
608
639
|
* @param {number} [dashboardSize=0.50] — 대시보드 분할 비율 (0.2~0.8)
|
|
640
|
+
* @deprecated dashboardSize — anchor=window|tab 모드에서는 무시됨
|
|
641
|
+
* @param {string} [dashboardAnchor='window'] — dashboard anchor 정책(window|tab)
|
|
609
642
|
* @returns {boolean}
|
|
610
643
|
*/
|
|
611
|
-
export function attachDashboardTab(sessionName, workerCount = 2, dashboardLayout = "single", dashboardSize = 0.40) {
|
|
644
|
+
export function attachDashboardTab(sessionName, workerCount = 2, dashboardLayout = "single", dashboardSize = 0.40, dashboardAnchor = "window") {
|
|
612
645
|
try { execSync("where wt.exe", { stdio: "ignore" }); } catch { return false; }
|
|
613
646
|
ensureWtProfile(workerCount);
|
|
614
|
-
const resolvedDashboardLayout = resolveDashboardLayout(dashboardLayout, workerCount);
|
|
615
|
-
|
|
616
|
-
// v7.1.3: 대시보드만 스플릿 (psmux attach 대신 tui-viewer 직접 실행)
|
|
617
|
-
// raw CLI 출력은 사용자에게 불필요 — 대시보드 로그만 표시
|
|
618
|
-
const viewerPath = join(import.meta.dirname, "tui-viewer.mjs").replace(/\\/g, "/");
|
|
619
|
-
const sizeStr = String(Math.round(dashboardSize * 100) / 100);
|
|
620
647
|
try {
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
"--profile", "triflux",
|
|
624
|
-
"--title", `▲ ${sessionName}`,
|
|
625
|
-
"--", "node", viewerPath, "--session", sessionName, "--result-dir", RESULT_DIR, "--layout", resolvedDashboardLayout,
|
|
626
|
-
], { detached: true, stdio: "ignore" });
|
|
648
|
+
const args = buildDashboardAttachArgs(sessionName, dashboardLayout, workerCount, dashboardAnchor);
|
|
649
|
+
const child = spawn("wt.exe", args, { detached: true, stdio: "ignore" });
|
|
627
650
|
child.unref();
|
|
628
|
-
try { spawn("wt.exe", ["-w", "0", "mf", "up"], { detached: true, stdio: "ignore" }).unref(); } catch {}
|
|
629
651
|
return true;
|
|
630
652
|
} catch { return false; }
|
|
631
653
|
}
|
|
@@ -664,6 +686,7 @@ export function getProgressSnapshots(sessionName, dispatches, lines = 15) {
|
|
|
664
686
|
* @param {number} [opts.progressIntervalSec=0]
|
|
665
687
|
* @param {boolean} [opts.autoAttach=false] — Windows Terminal 자동 attach
|
|
666
688
|
* @param {string} [opts.dashboardLayout='single'] — dashboard viewer 레이아웃
|
|
689
|
+
* @param {string} [opts.dashboardAnchor='window'] — dashboard anchor 정책(window|tab)
|
|
667
690
|
* @param {AbortSignal} [opts.signal] — abort 시 자동 세션 정리
|
|
668
691
|
* @param {number} [opts.maxIdleSec=0] — 유휴 시 자동 정리 (0=비활성)
|
|
669
692
|
* @returns {Promise<{
|
|
@@ -683,6 +706,7 @@ export async function runHeadlessInteractive(sessionName, assignments, opts = {}
|
|
|
683
706
|
autoAttach = false,
|
|
684
707
|
dashboard = false,
|
|
685
708
|
dashboardSize = 0.40,
|
|
709
|
+
dashboardAnchor = "window",
|
|
686
710
|
signal,
|
|
687
711
|
maxIdleSec = 0,
|
|
688
712
|
...runOpts
|
|
@@ -704,6 +728,7 @@ export async function runHeadlessInteractive(sessionName, assignments, opts = {}
|
|
|
704
728
|
assignments.length,
|
|
705
729
|
event.dashboardLayout || resolveDashboardLayout(headlessOpts.dashboardLayout, assignments.length),
|
|
706
730
|
dashboardSize,
|
|
731
|
+
dashboardAnchor,
|
|
707
732
|
);
|
|
708
733
|
} else {
|
|
709
734
|
autoAttachTerminal(sessionName, {}, assignments.length);
|