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.
Files changed (103) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +1 -1
  4. package/hooks/hooks.json +56 -51
  5. package/hub/pipeline/index.mjs +318 -318
  6. package/hub/routing/q-learning.mjs +2 -1
  7. package/hub/schema.sql +146 -146
  8. package/hub/team/cli/commands/kill.mjs +37 -37
  9. package/hub/team/cli/commands/start/index.mjs +3 -2
  10. package/hub/team/cli/commands/start/parse-args.mjs +5 -0
  11. package/hub/team/cli/commands/start/start-headless.mjs +2 -1
  12. package/hub/team/cli/commands/stop.mjs +31 -31
  13. package/hub/team/cli/commands/task.mjs +30 -30
  14. package/hub/team/cli/help.mjs +41 -40
  15. package/hub/team/cli/services/hub-client.mjs +208 -208
  16. package/hub/team/cli/services/native-control.mjs +118 -118
  17. package/hub/team/cli/services/runtime-mode.mjs +62 -62
  18. package/hub/team/cli/services/state-store.mjs +48 -48
  19. package/hub/team/dashboard-anchor.mjs +14 -0
  20. package/hub/team/dashboard.mjs +274 -274
  21. package/hub/team/headless.mjs +44 -19
  22. package/hub/team/native.mjs +649 -649
  23. package/hub/tools.mjs +554 -554
  24. package/hub/workers/delegator-mcp.mjs +21 -1
  25. package/package.json +1 -1
  26. package/scripts/__tests__/remote-spawn-transfer.test.mjs +117 -0
  27. package/scripts/__tests__/remote-spawn.test.mjs +78 -0
  28. package/scripts/cache-buildup.mjs +401 -0
  29. package/scripts/headless-guard.mjs +10 -3
  30. package/scripts/hub-ensure.mjs +120 -120
  31. package/scripts/lib/mcp-filter.mjs +720 -720
  32. package/scripts/lib/remote-spawn-transfer.mjs +196 -0
  33. package/scripts/mcp-check.mjs +237 -127
  34. package/scripts/mcp-gateway-ensure.mjs +6 -8
  35. package/scripts/mcp-gateway-integration-test.mjs +228 -0
  36. package/scripts/mcp-gateway-start.mjs +42 -16
  37. package/scripts/mcp-gateway-start.ps1 +17 -14
  38. package/scripts/mcp-gateway-verify.mjs +1 -1
  39. package/scripts/preflight-cache.mjs +137 -137
  40. package/scripts/remote-spawn.mjs +404 -40
  41. package/scripts/setup.mjs +18 -0
  42. package/scripts/tfx-route-worker.mjs +165 -165
  43. package/scripts/tfx-route.sh +85 -16
  44. package/scripts/token-snapshot.mjs +575 -575
  45. package/skills/tfx-analysis/SKILL.md +101 -101
  46. package/skills/tfx-autopilot/SKILL.md +112 -112
  47. package/skills/tfx-autoresearch/SKILL.md +1 -0
  48. package/skills/tfx-autoroute/SKILL.md +184 -184
  49. package/skills/tfx-codex-swarm/SKILL.md +449 -0
  50. package/skills/tfx-codex-swarm/evals/evals.json +26 -0
  51. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +33 -0
  52. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +42 -0
  53. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +11 -0
  54. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +87 -0
  55. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +35 -0
  56. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +275 -0
  57. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +56 -0
  58. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +5 -0
  59. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +11 -0
  60. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +92 -0
  61. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +71 -0
  62. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +264 -0
  63. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +113 -0
  64. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +5 -0
  65. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +32 -0
  66. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +9 -0
  67. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +96 -0
  68. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +38 -0
  69. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +151 -0
  70. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +51 -0
  71. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +5 -0
  72. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +9 -0
  73. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +127 -0
  74. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +57 -0
  75. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +129 -0
  76. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +84 -0
  77. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +5 -0
  78. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +27 -0
  79. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +8 -0
  80. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +98 -0
  81. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +65 -0
  82. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +123 -0
  83. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +66 -0
  84. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +5 -0
  85. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +8 -0
  86. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +88 -0
  87. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +40 -0
  88. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +130 -0
  89. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +61 -0
  90. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +5 -0
  91. package/skills/tfx-profile/SKILL.md +141 -51
  92. package/skills/tfx-qa/SKILL.md +117 -117
  93. package/skills/tfx-remote-spawn/references/hosts.json +16 -16
  94. package/skills/tfx-review/SKILL.md +51 -51
  95. package/skills/tfx-setup/SKILL.md +20 -0
  96. package/tui/gemini-profile.mjs +254 -0
  97. package/tui/setup.mjs +36 -1
  98. package/scripts/claude-logged.ps1 +0 -54
  99. package/scripts/demo-tui.mjs +0 -59
  100. package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +0 -1
  101. package/skills/.omc/state/idle-notif-cooldown.json +0 -3
  102. package/skills/.omc/state/last-tool-error.json +0 -7
  103. package/skills/.omc/state/subagent-tracking.json +0 -7
@@ -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
- return backend.buildArgs(promptExpr, resultFile, { ...opts, model });
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
- try { spawn("wt.exe", ["-w", "0", "mf", "up"], { detached: true, stdio: "ignore" }).unref(); } catch { /* 무시 */ }
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 child = spawn("wt.exe", [
622
- "-w", "0", "sp", "-H", "-s", sizeStr,
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);