triflux 10.4.0 → 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.
Files changed (391) hide show
  1. package/.claude-plugin/marketplace.json +34 -0
  2. package/.claude-plugin/plugin.json +22 -0
  3. package/bin/tfx-doctor-tui.mjs +1 -1
  4. package/bin/tfx-doctor.mjs +6 -1
  5. package/bin/tfx-profile.mjs +1 -1
  6. package/bin/tfx-setup-tui.mjs +1 -1
  7. package/bin/tfx-setup.mjs +6 -1
  8. package/bin/triflux.mjs +2396 -1140
  9. package/config/mcp-registry.json +29 -0
  10. package/hooks/agent-route-guard.mjs +12 -8
  11. package/hooks/cross-review-tracker.mjs +21 -8
  12. package/hooks/error-context.mjs +19 -7
  13. package/hooks/hook-adaptive-collector.mjs +18 -16
  14. package/hooks/hook-manager.mjs +93 -32
  15. package/hooks/hook-orchestrator.mjs +108 -24
  16. package/hooks/hook-registry.json +267 -256
  17. package/hooks/keyword-rules.json +6 -10
  18. package/hooks/lib/resolve-root.mjs +1 -1
  19. package/hooks/mcp-config-watcher.mjs +6 -2
  20. package/hooks/pipeline-stop.mjs +3 -6
  21. package/hooks/safety-guard.mjs +99 -28
  22. package/hooks/session-start-fast.mjs +143 -0
  23. package/hooks/subagent-verifier.mjs +5 -4
  24. package/hub/account-broker.mjs +256 -60
  25. package/hub/adaptive-diagnostic.mjs +75 -48
  26. package/hub/adaptive-inject.mjs +96 -58
  27. package/hub/adaptive-memory.mjs +156 -42
  28. package/hub/adaptive.mjs +60 -31
  29. package/hub/assign-callbacks.mjs +163 -126
  30. package/hub/bridge.mjs +0 -1
  31. package/hub/cli-adapter-base.mjs +200 -48
  32. package/hub/codex-adapter.mjs +76 -96
  33. package/hub/codex-compat.mjs +3 -3
  34. package/hub/codex-preflight.mjs +63 -37
  35. package/hub/delegator/contracts.mjs +19 -23
  36. package/hub/delegator/index.mjs +14 -14
  37. package/hub/delegator/service.mjs +88 -64
  38. package/hub/delegator/tool-definitions.mjs +35 -35
  39. package/hub/fullcycle.mjs +33 -17
  40. package/hub/gemini-adapter.mjs +69 -94
  41. package/hub/hitl.mjs +202 -143
  42. package/hub/intent.mjs +161 -38
  43. package/hub/lib/cache-guard.mjs +43 -17
  44. package/hub/lib/mcp-response-cache.mjs +66 -32
  45. package/hub/lib/memory-store.mjs +285 -111
  46. package/hub/lib/path-utils.mjs +35 -37
  47. package/hub/lib/process-utils.mjs +106 -37
  48. package/hub/lib/spawn-trace.mjs +527 -0
  49. package/hub/lib/ssh-command.mjs +34 -4
  50. package/hub/lib/ssh-retry.mjs +5 -1
  51. package/hub/lib/uuidv7.mjs +4 -3
  52. package/hub/memory-doctor.mjs +266 -106
  53. package/hub/middleware/request-logger.mjs +61 -34
  54. package/hub/paths.mjs +9 -9
  55. package/hub/pipeline/gates/confidence.mjs +34 -15
  56. package/hub/pipeline/gates/consensus.mjs +27 -15
  57. package/hub/pipeline/gates/index.mjs +7 -3
  58. package/hub/pipeline/gates/selfcheck.mjs +57 -19
  59. package/hub/pipeline/index.mjs +77 -42
  60. package/hub/pipeline/state.mjs +10 -10
  61. package/hub/pipeline/transitions.mjs +40 -23
  62. package/hub/platform.mjs +57 -48
  63. package/hub/promote-penalties.mjs +25 -7
  64. package/hub/quality/deslop.mjs +70 -49
  65. package/hub/research.mjs +32 -25
  66. package/hub/router.mjs +924 -791
  67. package/hub/routing/complexity.mjs +132 -29
  68. package/hub/routing/index.mjs +17 -12
  69. package/hub/routing/q-learning.mjs +76 -28
  70. package/hub/server.mjs +4 -4
  71. package/hub/session-fingerprint.mjs +127 -61
  72. package/hub/state.mjs +84 -43
  73. package/hub/store-adapter.mjs +59 -26
  74. package/hub/store.mjs +356 -153
  75. package/hub/team/agent-map.json +22 -7
  76. package/hub/team/ansi.mjs +186 -122
  77. package/hub/team/backend.mjs +28 -10
  78. package/hub/team/cli/commands/attach.mjs +57 -37
  79. package/hub/team/cli/commands/control.mjs +29 -8
  80. package/hub/team/cli/commands/debug.mjs +95 -74
  81. package/hub/team/cli/commands/focus.mjs +80 -53
  82. package/hub/team/cli/commands/interrupt.mjs +18 -6
  83. package/hub/team/cli/commands/kill.mjs +16 -5
  84. package/hub/team/cli/commands/list.mjs +31 -24
  85. package/hub/team/cli/commands/send.mjs +19 -6
  86. package/hub/team/cli/commands/start/index.mjs +154 -31
  87. package/hub/team/cli/commands/start/parse-args.mjs +38 -11
  88. package/hub/team/cli/commands/start/start-headless.mjs +112 -36
  89. package/hub/team/cli/commands/start/start-in-process.mjs +50 -40
  90. package/hub/team/cli/commands/start/start-mux.mjs +122 -73
  91. package/hub/team/cli/commands/start/start-wt.mjs +86 -69
  92. package/hub/team/cli/commands/status.mjs +43 -14
  93. package/hub/team/cli/commands/stop.mjs +11 -4
  94. package/hub/team/cli/commands/task.mjs +8 -3
  95. package/hub/team/cli/commands/tasks.mjs +13 -13
  96. package/hub/team/cli/index.mjs +2 -2
  97. package/hub/team/cli/manifest.mjs +38 -8
  98. package/hub/team/cli/render.mjs +52 -30
  99. package/hub/team/cli/services/attach-fallback.mjs +74 -54
  100. package/hub/team/cli/services/hub-client.mjs +42 -14
  101. package/hub/team/cli/services/member-selector.mjs +37 -30
  102. package/hub/team/cli/services/native-control.mjs +143 -116
  103. package/hub/team/cli/services/runtime-mode.mjs +2 -1
  104. package/hub/team/cli/services/state-store.mjs +25 -8
  105. package/hub/team/cli/services/task-model.mjs +40 -30
  106. package/hub/team/conductor-mesh-bridge.mjs +24 -23
  107. package/hub/team/conductor.mjs +8 -4
  108. package/hub/team/dashboard-anchor.mjs +4 -5
  109. package/hub/team/dashboard-layout.mjs +3 -1
  110. package/hub/team/dashboard-open.mjs +41 -21
  111. package/hub/team/dashboard.mjs +76 -28
  112. package/hub/team/event-log.mjs +18 -10
  113. package/hub/team/handoff.mjs +31 -15
  114. package/hub/team/headless.mjs +2 -1
  115. package/hub/team/health-probe.mjs +69 -54
  116. package/hub/team/launcher-template.mjs +16 -13
  117. package/hub/team/native-supervisor.mjs +65 -21
  118. package/hub/team/native.mjs +74 -35
  119. package/hub/team/nativeProxy.mjs +184 -113
  120. package/hub/team/notify.mjs +120 -77
  121. package/hub/team/orchestrator.mjs +166 -161
  122. package/hub/team/pane.mjs +12 -7
  123. package/hub/team/process-cleanup.mjs +25 -16
  124. package/hub/team/psmux.mjs +491 -201
  125. package/hub/team/remote-probe.mjs +68 -52
  126. package/hub/team/remote-session.mjs +117 -59
  127. package/hub/team/remote-watcher.mjs +61 -33
  128. package/hub/team/routing.mjs +51 -25
  129. package/hub/team/runtime-strategy.mjs +3 -1
  130. package/hub/team/session.mjs +675 -611
  131. package/hub/team/shared.mjs +13 -13
  132. package/hub/team/staleState.mjs +72 -30
  133. package/hub/team/swarm-locks.mjs +15 -13
  134. package/hub/team/swarm-planner.mjs +32 -21
  135. package/hub/team/swarm-reconciler.mjs +48 -23
  136. package/hub/team/tui-lite.mjs +266 -68
  137. package/hub/team/tui-remote-adapter.mjs +14 -10
  138. package/hub/team/tui-viewer.mjs +99 -43
  139. package/hub/team/tui.mjs +708 -271
  140. package/hub/team/worktree-lifecycle.mjs +152 -58
  141. package/hub/team/wt-manager.mjs +24 -14
  142. package/hub/token-mode.mjs +71 -71
  143. package/hub/tray.mjs +411 -368
  144. package/hub/workers/claude-worker.mjs +162 -118
  145. package/hub/workers/codex-mcp.mjs +558 -507
  146. package/hub/workers/delegator-mcp.mjs +507 -333
  147. package/hub/workers/factory.mjs +21 -21
  148. package/hub/workers/gemini-worker.mjs +115 -84
  149. package/hub/workers/interface.mjs +6 -1
  150. package/hub/workers/worker-utils.mjs +21 -14
  151. package/hud/colors.mjs +27 -9
  152. package/hud/constants.mjs +162 -26
  153. package/hud/context-monitor.mjs +82 -41
  154. package/hud/hud-qos-status.mjs +129 -49
  155. package/hud/mission-board.mjs +6 -3
  156. package/hud/providers/claude.mjs +226 -115
  157. package/hud/providers/codex.mjs +62 -22
  158. package/hud/providers/gemini.mjs +168 -56
  159. package/hud/renderers.mjs +384 -119
  160. package/hud/terminal.mjs +101 -31
  161. package/hud/utils.mjs +78 -38
  162. package/mesh/index.mjs +11 -5
  163. package/mesh/mesh-budget.mjs +18 -9
  164. package/mesh/mesh-heartbeat.mjs +1 -1
  165. package/mesh/mesh-queue.mjs +3 -5
  166. package/mesh/mesh-router.mjs +5 -4
  167. package/package.json +56 -21
  168. package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
  169. package/scripts/__tests__/keyword-detector.test.mjs +77 -28
  170. package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
  171. package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
  172. package/scripts/__tests__/remote-spawn.test.mjs +10 -4
  173. package/scripts/__tests__/session-start-fast.test.mjs +36 -0
  174. package/scripts/__tests__/skill-template.test.mjs +98 -50
  175. package/scripts/__tests__/smoke.test.mjs +1 -1
  176. package/scripts/__tests__/spawn-trace.test.mjs +102 -0
  177. package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
  178. package/scripts/cache-doctor.mjs +11 -4
  179. package/scripts/cache-warmup.mjs +96 -37
  180. package/scripts/claudemd-sync.mjs +27 -17
  181. package/scripts/codex-gateway-preflight.mjs +52 -37
  182. package/scripts/codex-mcp-gateway-sync.mjs +59 -39
  183. package/scripts/config-audit.mjs +232 -0
  184. package/scripts/convert-to-tmpl.mjs +54 -0
  185. package/scripts/cross-review-gate.mjs +35 -12
  186. package/scripts/cross-review-tracker.mjs +21 -8
  187. package/scripts/demo.mjs +35 -17
  188. package/scripts/doctor-diagnose.mjs +284 -0
  189. package/scripts/gen-skill-docs.mjs +7 -2
  190. package/scripts/gen-skill-manifest.mjs +2 -1
  191. package/scripts/headless-guard.mjs +86 -48
  192. package/scripts/hub-ensure.mjs +139 -120
  193. package/scripts/keyword-detector.mjs +293 -272
  194. package/scripts/keyword-rules-expander.mjs +538 -521
  195. package/scripts/lib/claudemd-scanner.mjs +6 -1
  196. package/scripts/lib/context.mjs +3 -3
  197. package/scripts/lib/cross-review-utils.mjs +6 -3
  198. package/scripts/lib/env-probe.mjs +47 -28
  199. package/scripts/lib/gemini-profiles.mjs +44 -10
  200. package/scripts/lib/handoff.mjs +33 -17
  201. package/scripts/lib/hook-utils.mjs +8 -6
  202. package/scripts/lib/keyword-rules.mjs +43 -19
  203. package/scripts/lib/logger.mjs +24 -24
  204. package/scripts/lib/mcp-filter.mjs +377 -239
  205. package/scripts/lib/mcp-guard-engine.mjs +194 -79
  206. package/scripts/lib/mcp-manifest.mjs +23 -13
  207. package/scripts/lib/mcp-server-catalog.mjs +355 -118
  208. package/scripts/lib/psmux-info.mjs +11 -6
  209. package/scripts/lib/remote-spawn-transfer.mjs +44 -14
  210. package/scripts/lib/skill-template.mjs +30 -7
  211. package/scripts/mcp-check.mjs +58 -39
  212. package/scripts/mcp-gateway-config.mjs +83 -39
  213. package/scripts/mcp-gateway-ensure.mjs +43 -35
  214. package/scripts/mcp-gateway-integration-test.mjs +70 -58
  215. package/scripts/mcp-gateway-start.mjs +126 -60
  216. package/scripts/mcp-gateway-verify.mjs +24 -22
  217. package/scripts/mcp-safety-guard.mjs +44 -11
  218. package/scripts/notion-read.mjs +669 -554
  219. package/scripts/pack.mjs +94 -89
  220. package/scripts/preflight-cache.mjs +27 -10
  221. package/scripts/preinstall.mjs +42 -13
  222. package/scripts/remote-spawn.mjs +309 -94
  223. package/scripts/run.cjs +8 -5
  224. package/scripts/session-spawn-helper.mjs +130 -39
  225. package/scripts/session-stale-cleanup.mjs +123 -0
  226. package/scripts/setup.mjs +941 -492
  227. package/scripts/test-lock.mjs +20 -7
  228. package/scripts/test-tfx-route-no-claude-native.mjs +61 -57
  229. package/scripts/tfx-batch-stats.mjs +117 -96
  230. package/scripts/tfx-gate-activate.mjs +11 -4
  231. package/scripts/tfx-route-post.mjs +87 -20
  232. package/scripts/tfx-route-worker.mjs +57 -51
  233. package/scripts/tfx-route.sh +41 -124
  234. package/scripts/tmp-cleanup.mjs +21 -7
  235. package/scripts/token-snapshot.mjs +204 -85
  236. package/skills/.omc/state/idle-notif-cooldown.json +1 -1
  237. package/skills/.omc/state/last-tool-error.json +1 -1
  238. package/skills/.omc/state/subagent-tracking.json +1 -1
  239. package/skills/_templates/base.md +1 -6
  240. package/skills/merge-worktree/SKILL.md.tmpl +144 -0
  241. package/skills/shared/telemetry-segment.md +6 -0
  242. package/skills/star-prompt/SKILL.md.tmpl +222 -0
  243. package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
  244. package/skills/tfx-analysis/skill.json +1 -6
  245. package/skills/tfx-auto/SKILL.md +1 -0
  246. package/skills/{tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md → tfx-auto-codex/SKILL.md.tmpl} +33 -4
  247. package/skills/tfx-auto-codex/skill.json +1 -3
  248. package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
  249. package/skills/tfx-autopilot/skill.json +1 -5
  250. package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
  251. package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
  252. package/skills/tfx-autoroute/skill.json +1 -7
  253. package/skills/tfx-codex/SKILL.md +1 -0
  254. package/skills/tfx-codex/skill.json +1 -3
  255. package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
  256. package/skills/tfx-codex-swarm/evals/evals.json +1 -1
  257. package/skills/tfx-codex-swarm/skill.json +1 -4
  258. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
  259. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
  260. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
  261. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
  262. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
  263. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
  264. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
  265. package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
  266. package/skills/tfx-debate/SKILL.md.tmpl +192 -0
  267. package/skills/tfx-debate/skill.json +1 -7
  268. package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
  269. package/skills/tfx-deep-analysis/skill.json +1 -5
  270. package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
  271. package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
  272. package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
  273. package/skills/tfx-deep-qa/skill.json +1 -6
  274. package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
  275. package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
  276. package/skills/tfx-doctor/SKILL.md +21 -0
  277. package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
  278. package/skills/tfx-doctor/skill.json +1 -3
  279. package/skills/tfx-find/SKILL.md +1 -0
  280. package/skills/tfx-forge/SKILL.md.tmpl +187 -0
  281. package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
  282. package/skills/tfx-fullcycle/skill.json +1 -6
  283. package/skills/{tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md → tfx-gemini/SKILL.md.tmpl} +16 -7
  284. package/skills/tfx-gemini/skill.json +1 -3
  285. package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
  286. package/skills/tfx-hooks/skill.json +1 -3
  287. package/skills/tfx-hub/SKILL.md.tmpl +212 -0
  288. package/skills/tfx-hub/skill.json +1 -3
  289. package/skills/tfx-index/SKILL.md +1 -0
  290. package/skills/tfx-index/skill.json +1 -6
  291. package/skills/tfx-interview/SKILL.md.tmpl +285 -0
  292. package/skills/tfx-multi/SKILL.md.tmpl +183 -0
  293. package/skills/tfx-multi/skill.json +1 -3
  294. package/skills/tfx-panel/SKILL.md.tmpl +189 -0
  295. package/skills/tfx-panel/skill.json +1 -7
  296. package/skills/tfx-persist/SKILL.md.tmpl +270 -0
  297. package/skills/tfx-persist/skill.json +1 -7
  298. package/skills/tfx-plan/SKILL.md +1 -0
  299. package/skills/tfx-plan/skill.json +1 -6
  300. package/skills/tfx-profile/SKILL.md.tmpl +239 -0
  301. package/skills/tfx-profile/skill.json +1 -3
  302. package/skills/tfx-prune/SKILL.md.tmpl +200 -0
  303. package/skills/tfx-prune/skill.json +1 -7
  304. package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
  305. package/skills/tfx-psmux-rules/skill.json +1 -4
  306. package/skills/tfx-qa/SKILL.md +1 -0
  307. package/skills/tfx-qa/skill.json +1 -6
  308. package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
  309. package/skills/tfx-ralph/skill.json +1 -4
  310. package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
  311. package/skills/tfx-remote-setup/skill.json +1 -3
  312. package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
  313. package/skills/tfx-remote-spawn/references/hosts.json +16 -16
  314. package/skills/tfx-remote-spawn/skill.json +1 -4
  315. package/skills/tfx-research/SKILL.md +1 -0
  316. package/skills/tfx-review/SKILL.md +1 -0
  317. package/skills/tfx-review/skill.json +1 -6
  318. package/skills/tfx-setup/SKILL.md.tmpl +504 -0
  319. package/skills/tfx-setup/skill.json +1 -3
  320. package/skills/tfx-swarm/SKILL.md +22 -0
  321. package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
  322. package/tui/codex-profile.mjs +457 -0
  323. package/tui/core.mjs +266 -0
  324. package/tui/doctor.mjs +375 -0
  325. package/tui/gemini-profile.mjs +299 -0
  326. package/tui/monitor-data.mjs +152 -0
  327. package/tui/monitor.mjs +339 -0
  328. package/tui/setup.mjs +533 -0
  329. package/CLAUDE.md +0 -193
  330. package/references/hosts.json +0 -33
  331. package/skills/tfx-workspace/async-tests/run-tests.sh +0 -203
  332. package/skills/tfx-workspace/evals/evals.json +0 -79
  333. package/skills/tfx-workspace/iteration-1/benchmark.json +0 -162
  334. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +0 -11
  335. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +0 -9
  336. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +0 -154
  337. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +0 -5
  338. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +0 -9
  339. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +0 -126
  340. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +0 -5
  341. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +0 -11
  342. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +0 -9
  343. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +0 -119
  344. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +0 -5
  345. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +0 -9
  346. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +0 -115
  347. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +0 -5
  348. package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +0 -10
  349. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +0 -8
  350. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +0 -86
  351. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +0 -5
  352. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +0 -8
  353. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +0 -81
  354. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +0 -5
  355. package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +0 -12
  356. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +0 -10
  357. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +0 -316
  358. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +0 -5
  359. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +0 -10
  360. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +0 -352
  361. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +0 -5
  362. package/skills/tfx-workspace/iteration-1/review.html +0 -1325
  363. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +0 -12
  364. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +0 -10
  365. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +0 -97
  366. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +0 -5
  367. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +0 -10
  368. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +0 -94
  369. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +0 -5
  370. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +0 -12
  371. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +0 -10
  372. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +0 -209
  373. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +0 -5
  374. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +0 -10
  375. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +0 -193
  376. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +0 -5
  377. package/skills/tfx-workspace/iteration-2/benchmark.json +0 -62
  378. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +0 -13
  379. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +0 -11
  380. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +0 -382
  381. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +0 -5
  382. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +0 -11
  383. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +0 -333
  384. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +0 -5
  385. package/skills/tfx-workspace/iteration-2/review.html +0 -1325
  386. package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +0 -217
  387. package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +0 -65
  388. package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +0 -94
  389. package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +0 -133
  390. package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +0 -426
  391. package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +0 -101
@@ -1,13 +1,20 @@
1
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { mkdirSync } from "node:fs";
3
- import { dirname, join } from "node:path";
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ readFileSync,
5
+ unlinkSync,
6
+ writeFileSync,
7
+ } from "node:fs";
4
8
  import { homedir } from "node:os";
9
+ import { dirname, join } from "node:path";
5
10
  import { fileURLToPath } from "node:url";
6
11
 
7
12
  export const PKG_ROOT = fileURLToPath(new URL("../../../../", import.meta.url));
8
13
  export const HUB_PID_DIR = join(homedir(), ".claude", "cache", "tfx-hub");
9
14
  export const TEAM_PROFILE = (() => {
10
- const raw = String(process.env.TFX_TEAM_PROFILE || "team").trim().toLowerCase();
15
+ const raw = String(process.env.TFX_TEAM_PROFILE || "team")
16
+ .trim()
17
+ .toLowerCase();
11
18
  return raw === "codex-team" ? "codex-team" : "team";
12
19
  })();
13
20
 
@@ -15,21 +22,28 @@ export const SESSION_ID = process.env.CLAUDE_SESSION_ID || `s${Date.now()}`;
15
22
 
16
23
  function getStatePath(sessionId) {
17
24
  if (sessionId) return join(HUB_PID_DIR, `team-state-${sessionId}.json`);
18
- return join(HUB_PID_DIR, TEAM_PROFILE === "codex-team" ? "team-state-codex-team.json" : "team-state.json");
25
+ return join(
26
+ HUB_PID_DIR,
27
+ TEAM_PROFILE === "codex-team"
28
+ ? "team-state-codex-team.json"
29
+ : "team-state.json",
30
+ );
19
31
  }
20
32
 
21
33
  export function loadTeamState(sessionId) {
22
34
  const resolvedId = sessionId || SESSION_ID;
23
35
  const sessionPath = getStatePath(resolvedId);
24
36
  try {
25
- if (existsSync(sessionPath)) return JSON.parse(readFileSync(sessionPath, "utf8"));
37
+ if (existsSync(sessionPath))
38
+ return JSON.parse(readFileSync(sessionPath, "utf8"));
26
39
  } catch {
27
40
  return null;
28
41
  }
29
42
  // 세션별 파일 없으면 기존 team-state.json fallback
30
43
  const legacyPath = getStatePath(null);
31
44
  try {
32
- if (existsSync(legacyPath)) return JSON.parse(readFileSync(legacyPath, "utf8"));
45
+ if (existsSync(legacyPath))
46
+ return JSON.parse(readFileSync(legacyPath, "utf8"));
33
47
  } catch {
34
48
  return null;
35
49
  }
@@ -39,7 +53,10 @@ export function loadTeamState(sessionId) {
39
53
  export function saveTeamState(state, sessionId) {
40
54
  const path = getStatePath(sessionId || state.sessionId || SESSION_ID);
41
55
  mkdirSync(dirname(path), { recursive: true });
42
- writeFileSync(path, JSON.stringify({ ...state, profile: TEAM_PROFILE }, null, 2) + "\n");
56
+ writeFileSync(
57
+ path,
58
+ JSON.stringify({ ...state, profile: TEAM_PROFILE }, null, 2) + "\n",
59
+ );
43
60
  }
44
61
 
45
62
  export function clearTeamState(sessionId) {
@@ -1,30 +1,40 @@
1
- export function buildTasks(subtasks, workers) {
2
- return subtasks.map((subtask, index) => ({
3
- id: `T${index + 1}`,
4
- title: subtask,
5
- owner: workers[index]?.name || null,
6
- status: "pending",
7
- depends_on: index === 0 ? [] : [`T${index}`],
8
- }));
9
- }
10
-
11
- export function normalizeTaskStatus(action) {
12
- const value = String(action || "").toLowerCase();
13
- if (value === "done" || value === "complete" || value === "completed") return "completed";
14
- if (value === "progress" || value === "in-progress" || value === "in_progress") return "in_progress";
15
- if (value === "pending") return "pending";
16
- return null;
17
- }
18
-
19
- export function updateTaskStatus(tasks = [], taskId, nextStatus) {
20
- const normalizedId = String(taskId || "").toUpperCase();
21
- const target = tasks.find((task) => String(task.id).toUpperCase() === normalizedId);
22
- if (!target) return { tasks, target: null };
23
-
24
- return {
25
- target: { ...target, status: nextStatus },
26
- tasks: tasks.map((task) => (
27
- String(task.id).toUpperCase() === normalizedId ? { ...task, status: nextStatus } : task
28
- )),
29
- };
30
- }
1
+ export function buildTasks(subtasks, workers) {
2
+ return subtasks.map((subtask, index) => ({
3
+ id: `T${index + 1}`,
4
+ title: subtask,
5
+ owner: workers[index]?.name || null,
6
+ status: "pending",
7
+ depends_on: index === 0 ? [] : [`T${index}`],
8
+ }));
9
+ }
10
+
11
+ export function normalizeTaskStatus(action) {
12
+ const value = String(action || "").toLowerCase();
13
+ if (value === "done" || value === "complete" || value === "completed")
14
+ return "completed";
15
+ if (
16
+ value === "progress" ||
17
+ value === "in-progress" ||
18
+ value === "in_progress"
19
+ )
20
+ return "in_progress";
21
+ if (value === "pending") return "pending";
22
+ return null;
23
+ }
24
+
25
+ export function updateTaskStatus(tasks = [], taskId, nextStatus) {
26
+ const normalizedId = String(taskId || "").toUpperCase();
27
+ const target = tasks.find(
28
+ (task) => String(task.id).toUpperCase() === normalizedId,
29
+ );
30
+ if (!target) return { tasks, target: null };
31
+
32
+ return {
33
+ target: { ...target, status: nextStatus },
34
+ tasks: tasks.map((task) =>
35
+ String(task.id).toUpperCase() === normalizedId
36
+ ? { ...task, status: nextStatus }
37
+ : task,
38
+ ),
39
+ };
40
+ }
@@ -14,10 +14,7 @@ const BRIDGE_AGENT_ID = "conductor";
14
14
  * @returns {object} Bridge API
15
15
  */
16
16
  export function createConductorMeshBridge(conductor, registry, opts = {}) {
17
- const {
18
- bridgeAgentId = BRIDGE_AGENT_ID,
19
- onMessage,
20
- } = opts;
17
+ const { bridgeAgentId = BRIDGE_AGENT_ID, onMessage } = opts;
21
18
 
22
19
  const sessionAgentMap = new Map();
23
20
  let attached = false;
@@ -49,12 +46,13 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
49
46
  }
50
47
 
51
48
  // Emit mesh event
52
- const msg = createMessage(
53
- MSG_TYPES.EVENT,
54
- bridgeAgentId,
55
- "*",
56
- { event: "stateChange", sessionId, from, to, reason },
57
- );
49
+ const msg = createMessage(MSG_TYPES.EVENT, bridgeAgentId, "*", {
50
+ event: "stateChange",
51
+ sessionId,
52
+ from,
53
+ to,
54
+ reason,
55
+ });
58
56
  emit(msg);
59
57
 
60
58
  // Unregister on terminal states
@@ -68,12 +66,10 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
68
66
  * Handle conductor completed events.
69
67
  */
70
68
  function handleCompleted(event) {
71
- const msg = createMessage(
72
- MSG_TYPES.EVENT,
73
- bridgeAgentId,
74
- "*",
75
- { event: "completed", sessionId: event.sessionId },
76
- );
69
+ const msg = createMessage(MSG_TYPES.EVENT, bridgeAgentId, "*", {
70
+ event: "completed",
71
+ sessionId: event.sessionId,
72
+ });
77
73
  emit(msg);
78
74
  }
79
75
 
@@ -81,12 +77,11 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
81
77
  * Handle conductor dead events.
82
78
  */
83
79
  function handleDead(event) {
84
- const msg = createMessage(
85
- MSG_TYPES.EVENT,
86
- bridgeAgentId,
87
- "*",
88
- { event: "dead", sessionId: event.sessionId, reason: event.reason },
89
- );
80
+ const msg = createMessage(MSG_TYPES.EVENT, bridgeAgentId, "*", {
81
+ event: "dead",
82
+ sessionId: event.sessionId,
83
+ reason: event.reason,
84
+ });
90
85
  emit(msg);
91
86
  }
92
87
 
@@ -117,5 +112,11 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
117
112
  attached = false;
118
113
  }
119
114
 
120
- return { attach, detach, get isAttached() { return attached; } };
115
+ return {
116
+ attach,
117
+ detach,
118
+ get isAttached() {
119
+ return attached;
120
+ },
121
+ };
121
122
  }
@@ -8,7 +8,7 @@
8
8
  // 3. Auto-restart (maxRestarts=3)
9
9
  // 4. JSONL event log (블랙박스 리코더)
10
10
 
11
- import { execFile, spawn } from "node:child_process";
11
+ import { execFile, spawn } from "../lib/spawn-trace.mjs";
12
12
  import { EventEmitter } from "node:events";
13
13
  import {
14
14
  copyFileSync,
@@ -22,7 +22,10 @@ import { createRegistry } from "../../mesh/mesh-registry.mjs";
22
22
  import { broker } from "../account-broker.mjs";
23
23
  import { killProcess } from "../platform.mjs";
24
24
  import { createConductorMeshBridge } from "./conductor-mesh-bridge.mjs";
25
- import { ensureConductorRegistry, getConductorRegistry } from "./conductor-registry.mjs";
25
+ import {
26
+ ensureConductorRegistry,
27
+ getConductorRegistry,
28
+ } from "./conductor-registry.mjs";
26
29
  import { createEventLog } from "./event-log.mjs";
27
30
  import { createHealthProbe } from "./health-probe.mjs";
28
31
  import { buildLauncher } from "./launcher-template.mjs";
@@ -86,7 +89,7 @@ export function createConductor(opts = {}) {
86
89
  const emitter = new EventEmitter();
87
90
  const sessions = new Map();
88
91
  let shuttingDown = false;
89
- let publicApi = null;
92
+ const publicApi = null;
90
93
 
91
94
  // 공유 event log (모든 세션 이벤트를 하나의 JSONL에)
92
95
  const eventLog = createEventLog(join(logsDir, "conductor-events.jsonl"));
@@ -180,7 +183,7 @@ export function createConductor(opts = {}) {
180
183
  execFn(
181
184
  "ssh",
182
185
  [`${sshUser}@${sshIp}`, "psmux", "kill-session", "-t", session.id],
183
- { timeout: 10_000 },
186
+ { timeout: 10_000, reason: "conductor:killRemoteSession" },
184
187
  () => {},
185
188
  );
186
189
  eventLog.append("remote_kill", {
@@ -376,6 +379,7 @@ export function createConductor(opts = {}) {
376
379
  child = spawn(launcher.command, {
377
380
  shell: true,
378
381
  env: { ...process.env, ...launcher.env, ...(session.config.env || {}) },
382
+ reason: `conductor:respawnSession:${session.id}`,
379
383
  stdio: ["pipe", "pipe", "pipe"],
380
384
  windowsHide: true,
381
385
  });
@@ -1,10 +1,9 @@
1
- const DASHBOARD_ANCHORS = new Set([
2
- "window",
3
- "tab",
4
- ]);
1
+ const DASHBOARD_ANCHORS = new Set(["window", "tab"]);
5
2
 
6
3
  export function normalizeDashboardAnchor(value) {
7
- const normalized = String(value ?? "").trim().toLowerCase();
4
+ const normalized = String(value ?? "")
5
+ .trim()
6
+ .toLowerCase();
8
7
  if (!normalized) return "window";
9
8
  return DASHBOARD_ANCHORS.has(normalized) ? normalized : "window";
10
9
  }
@@ -12,7 +12,9 @@ const DASHBOARD_LAYOUTS = new Set([
12
12
  ]);
13
13
 
14
14
  export function normalizeDashboardLayout(value, { allowAuto = true } = {}) {
15
- const normalized = String(value ?? "").trim().toLowerCase();
15
+ const normalized = String(value ?? "")
16
+ .trim()
17
+ .toLowerCase();
16
18
  if (!normalized) return "single";
17
19
  if (normalized === "auto" && !allowAuto) return "single";
18
20
  return DASHBOARD_LAYOUTS.has(normalized) ? normalized : "single";
@@ -1,4 +1,4 @@
1
- import { spawn } from "node:child_process";
1
+ import { spawn } from "../lib/spawn-trace.mjs";
2
2
 
3
3
  import { psmuxExec } from "./psmux.mjs";
4
4
  import {
@@ -10,7 +10,9 @@ import {
10
10
  } from "./session.mjs";
11
11
 
12
12
  function sanitizeWindowTitle(value, fallback = "triflux") {
13
- const text = String(value || "").replace(/[\r\n]+/g, " ").trim();
13
+ const text = String(value || "")
14
+ .replace(/[\r\n]+/g, " ")
15
+ .trim();
14
16
  return text || fallback;
15
17
  }
16
18
 
@@ -19,7 +21,9 @@ function sanitizeSessionName(value) {
19
21
  }
20
22
 
21
23
  function sanitizeWorkingDirectory(value) {
22
- const text = String(value || "").replace(/[\r\n\x00-\x1f]/g, "").trim();
24
+ const text = String(value || "")
25
+ .replace(/[\r\n\x00-\x1f]/g, "")
26
+ .trim();
23
27
  return text || process.cwd();
24
28
  }
25
29
 
@@ -32,7 +36,10 @@ export function parseWorkerNumber(value) {
32
36
  return null;
33
37
  }
34
38
 
35
- export function decideDashboardOpenMode({ openAll = false, hasWtSession = !!process.env.WT_SESSION } = {}) {
39
+ export function decideDashboardOpenMode({
40
+ openAll = false,
41
+ hasWtSession = !!process.env.WT_SESSION,
42
+ } = {}) {
36
43
  if (openAll) return hasWtSession ? "tab" : "window";
37
44
  return hasWtSession ? "split" : "window";
38
45
  }
@@ -44,19 +51,32 @@ function spawnWindowsTerminal(spec, opts = {}) {
44
51
  mode = "window",
45
52
  title = "triflux",
46
53
  cwd = process.cwd(),
47
- split = { orientation: "H", size: 0.50 },
54
+ split = { orientation: "H", size: 0.5 },
48
55
  } = opts;
49
56
 
50
57
  const safeTitle = sanitizeWindowTitle(title);
51
58
  const safeCwd = sanitizeWorkingDirectory(cwd);
52
59
  const orientation = split?.orientation === "V" ? "V" : "H";
53
- const size = Number.isFinite(split?.size) ? Math.min(0.8, Math.max(0.2, split.size)) : 0.50;
54
- const baseArgs = ["--profile", "triflux", "--title", safeTitle, "-d", safeCwd, "--", spec.command, ...spec.args];
55
- const args = mode === "split"
56
- ? ["-w", "0", "sp", `-${orientation}`, "-s", String(size), ...baseArgs]
57
- : mode === "tab"
58
- ? ["-w", "0", "nt", ...baseArgs]
59
- : ["-w", "new", ...baseArgs];
60
+ const size = Number.isFinite(split?.size)
61
+ ? Math.min(0.8, Math.max(0.2, split.size))
62
+ : 0.5;
63
+ const baseArgs = [
64
+ "--profile",
65
+ "triflux",
66
+ "--title",
67
+ safeTitle,
68
+ "-d",
69
+ safeCwd,
70
+ "--",
71
+ spec.command,
72
+ ...spec.args,
73
+ ];
74
+ const args =
75
+ mode === "split"
76
+ ? ["-w", "0", "sp", `-${orientation}`, "-s", String(size), ...baseArgs]
77
+ : mode === "tab"
78
+ ? ["-w", "0", "nt", ...baseArgs]
79
+ : ["-w", "new", ...baseArgs];
60
80
 
61
81
  const child = spawn("wt.exe", args, {
62
82
  detached: true,
@@ -78,7 +98,8 @@ export function focusManagedPane(target, opts = {}) {
78
98
 
79
99
  if (!paneRef) return false;
80
100
  try {
81
- if (detectMultiplexer() === "psmux") psmuxExec(["select-pane", "-t", paneRef]);
101
+ if (detectMultiplexer() === "psmux")
102
+ psmuxExec(["select-pane", "-t", paneRef]);
82
103
  else tmuxExec(`select-pane -t ${paneRef}`);
83
104
  return true;
84
105
  } catch {
@@ -87,12 +108,7 @@ export function focusManagedPane(target, opts = {}) {
87
108
  }
88
109
 
89
110
  export function openHeadlessDashboardTarget(sessionName, opts = {}) {
90
- const {
91
- worker = null,
92
- openAll = false,
93
- cwd = process.cwd(),
94
- title,
95
- } = opts;
111
+ const { worker = null, openAll = false, cwd = process.cwd(), title } = opts;
96
112
 
97
113
  const safeSession = sanitizeSessionName(sessionName);
98
114
  const workerNumber = worker == null ? null : parseWorkerNumber(worker);
@@ -136,12 +152,16 @@ export function openDashboardRuntimeTarget(runtime, opts = {}) {
136
152
  });
137
153
  }
138
154
 
139
- if ((teammateMode === "wt" || String(targetPane).startsWith("wt:")) && !openAll) {
155
+ if (
156
+ (teammateMode === "wt" || String(targetPane).startsWith("wt:")) &&
157
+ !openAll
158
+ ) {
140
159
  return focusManagedPane(targetPane, { teammateMode: "wt", layout });
141
160
  }
142
161
 
143
162
  try {
144
- if (!openAll && targetPane) focusManagedPane(targetPane, { teammateMode, layout });
163
+ if (!openAll && targetPane)
164
+ focusManagedPane(targetPane, { teammateMode, layout });
145
165
  return spawnWindowsTerminal(resolveAttachCommand(sessionName), {
146
166
  mode: decideDashboardOpenMode({ openAll }),
147
167
  title: title || `▲ ${sanitizeSessionName(sessionName)}`,
@@ -6,7 +6,7 @@
6
6
  // node hub/team/dashboard.mjs --session <세션이름> [--interval 2]
7
7
  // node hub/team/dashboard.mjs --team <팀이름> [--interval 2]
8
8
  import { get } from "node:http";
9
- import { AMBER, GREEN, RED, GRAY, DIM, BOLD, RESET } from "./shared.mjs";
9
+ import { AMBER, BOLD, DIM, GRAY, GREEN, RED, RESET } from "./shared.mjs";
10
10
 
11
11
  /**
12
12
  * HTTP GET JSON
@@ -19,11 +19,18 @@ function fetchJson(url) {
19
19
  let data = "";
20
20
  res.on("data", (chunk) => (data += chunk));
21
21
  res.on("end", () => {
22
- try { resolve(JSON.parse(data)); } catch { resolve(null); }
22
+ try {
23
+ resolve(JSON.parse(data));
24
+ } catch {
25
+ resolve(null);
26
+ }
23
27
  });
24
28
  });
25
29
  req.on("error", () => resolve(null));
26
- req.on("timeout", () => { req.destroy(); resolve(null); });
30
+ req.on("timeout", () => {
31
+ req.destroy();
32
+ resolve(null);
33
+ });
27
34
  });
28
35
  }
29
36
 
@@ -77,10 +84,14 @@ function formatUptime(ms) {
77
84
  */
78
85
  function statusIcon(status) {
79
86
  switch (status) {
80
- case "completed": return `${GREEN}✓${RESET}`;
81
- case "in_progress": return `${AMBER}●${RESET}`;
82
- case "failed": return `${RED}✗${RESET}`;
83
- default: return `${GRAY}○${RESET}`;
87
+ case "completed":
88
+ return `${GREEN}✓${RESET}`;
89
+ case "in_progress":
90
+ return `${AMBER}●${RESET}`;
91
+ case "failed":
92
+ return `${RED}✗${RESET}`;
93
+ default:
94
+ return `${GRAY}○${RESET}`;
84
95
  }
85
96
  }
86
97
 
@@ -118,7 +129,12 @@ function buildMemberList(hubTasks, supervisorMembers, teamState) {
118
129
  members.push({
119
130
  name: m.name,
120
131
  cli: m.cli || "",
121
- status: m.status === "running" ? "in_progress" : m.status === "exited" ? "completed" : m.status,
132
+ status:
133
+ m.status === "running"
134
+ ? "in_progress"
135
+ : m.status === "exited"
136
+ ? "completed"
137
+ : m.status,
122
138
  subject: "",
123
139
  preview: m.lastPreview || "",
124
140
  });
@@ -128,7 +144,9 @@ function buildMemberList(hubTasks, supervisorMembers, teamState) {
128
144
 
129
145
  // teamState 폴백 (하위 호환)
130
146
  const panes = teamState?.panes || {};
131
- for (const [, paneInfo] of Object.entries(panes).filter(([, v]) => v.role !== "dashboard" && v.role !== "lead")) {
147
+ for (const [, paneInfo] of Object.entries(panes).filter(
148
+ ([, v]) => v.role !== "dashboard" && v.role !== "lead",
149
+ )) {
132
150
  members.push({
133
151
  name: paneInfo.agentId || paneInfo.name || "?",
134
152
  cli: paneInfo.cli || "",
@@ -162,27 +180,41 @@ export async function renderDashboard(sessionName, opts = {}) {
162
180
  // 데이터 수집 (병렬)
163
181
  const [hubStatus, taskListRes, supervisorRes] = await Promise.all([
164
182
  fetchJson(`${hubUrl}/status`),
165
- teamName ? fetchPost(`${hubUrl}/bridge/team/task-list`, { team_name: teamName }) : null,
183
+ teamName
184
+ ? fetchPost(`${hubUrl}/bridge/team/task-list`, { team_name: teamName })
185
+ : null,
166
186
  supervisorUrl ? fetchJson(`${supervisorUrl}/status`) : null,
167
187
  ]);
168
188
 
169
189
  const hubOnline = !!hubStatus;
170
- const hubState = hubOnline ? `${GREEN}● online${RESET}` : `${RED}● offline${RESET}`;
171
- const uptime = hubStatus?.hub?.uptime ? formatUptime(hubStatus.hub.uptime) : "-";
190
+ const hubState = hubOnline
191
+ ? `${GREEN}● online${RESET}`
192
+ : `${RED}● offline${RESET}`;
193
+ const uptime = hubStatus?.hub?.uptime
194
+ ? formatUptime(hubStatus.hub.uptime)
195
+ : "-";
172
196
  const queueSize = hubStatus?.hub?.queue_depth ?? 0;
173
197
 
174
198
  // Hub task 데이터
175
- const hubTasks = taskListRes?.ok ? (taskListRes.data?.tasks || []) : [];
176
- const completedCount = hubTasks.filter((t) => t.status === "completed").length;
199
+ const hubTasks = taskListRes?.ok ? taskListRes.data?.tasks || [] : [];
200
+ const completedCount = hubTasks.filter(
201
+ (t) => t.status === "completed",
202
+ ).length;
177
203
  const totalCount = hubTasks.length;
178
204
 
179
205
  // Supervisor 멤버 데이터
180
- const supervisorMembers = supervisorRes?.ok ? (supervisorRes.data?.members || []) : [];
206
+ const supervisorMembers = supervisorRes?.ok
207
+ ? supervisorRes.data?.members || []
208
+ : [];
181
209
 
182
210
  // 헤더
183
211
  const progress = totalCount > 0 ? ` ${completedCount}/${totalCount}` : "";
184
- console.log(`${AMBER}┌─ ${sessionName}${progress} ${GRAY}${"─".repeat(Math.max(0, W - sessionName.length - progress.length - 3))}${AMBER}┐${RESET}`);
185
- console.log(`${AMBER}│${RESET} Hub: ${hubState} Uptime: ${DIM}${uptime}${RESET} Queue: ${DIM}${queueSize}${RESET}`);
212
+ console.log(
213
+ `${AMBER}┌─ ${sessionName}${progress} ${GRAY}${"─".repeat(Math.max(0, W - sessionName.length - progress.length - 3))}${AMBER}┐${RESET}`,
214
+ );
215
+ console.log(
216
+ `${AMBER}│${RESET} Hub: ${hubState} Uptime: ${DIM}${uptime}${RESET} Queue: ${DIM}${queueSize}${RESET}`,
217
+ );
186
218
  console.log(`${AMBER}│${RESET}`);
187
219
 
188
220
  // 멤버/워커 렌더링
@@ -194,20 +226,29 @@ export async function renderDashboard(sessionName, opts = {}) {
194
226
  for (const m of members) {
195
227
  const icon = statusIcon(m.status);
196
228
  const label = `[${m.name}]`;
197
- const cliTag = m.cli ? m.cli.charAt(0).toUpperCase() + m.cli.slice(1) : "";
229
+ const cliTag = m.cli
230
+ ? m.cli.charAt(0).toUpperCase() + m.cli.slice(1)
231
+ : "";
198
232
 
199
233
  // 진행률 추정
200
- const pct = m.status === "completed" ? 100
201
- : m.status === "in_progress" ? 50
202
- : m.status === "failed" ? 100
203
- : 0;
234
+ const pct =
235
+ m.status === "completed"
236
+ ? 100
237
+ : m.status === "in_progress"
238
+ ? 50
239
+ : m.status === "failed"
240
+ ? 100
241
+ : 0;
204
242
 
205
- console.log(`${AMBER}│${RESET} ${BOLD}${label}${RESET} ${cliTag} ${icon} ${m.status || "pending"} ${progressBar(pct)}`);
243
+ console.log(
244
+ `${AMBER}│${RESET} ${BOLD}${label}${RESET} ${cliTag} ${icon} ${m.status || "pending"} ${progressBar(pct)}`,
245
+ );
206
246
 
207
247
  // 미리보기: supervisor lastPreview > task subject
208
248
  const preview = m.preview || m.subject || "";
209
249
  if (preview) {
210
- const truncated = preview.length > W - 8 ? preview.slice(0, W - 11) + "..." : preview;
250
+ const truncated =
251
+ preview.length > W - 8 ? preview.slice(0, W - 11) + "..." : preview;
211
252
  console.log(`${AMBER}│${RESET} ${DIM}> ${truncated}${RESET}`);
212
253
  }
213
254
  console.log(`${AMBER}│${RESET}`);
@@ -228,10 +269,12 @@ async function loadTeamState() {
228
269
  const sessionId = process.env.CLAUDE_SESSION_ID;
229
270
  if (sessionId) {
230
271
  const sessionPath = join(hubDir, `team-state-${sessionId}.json`);
231
- if (existsSync(sessionPath)) return JSON.parse(readFileSync(sessionPath, "utf8"));
272
+ if (existsSync(sessionPath))
273
+ return JSON.parse(readFileSync(sessionPath, "utf8"));
232
274
  }
233
275
  const legacyPath = join(hubDir, "team-state.json");
234
- if (existsSync(legacyPath)) return JSON.parse(readFileSync(legacyPath, "utf8"));
276
+ if (existsSync(legacyPath))
277
+ return JSON.parse(readFileSync(legacyPath, "utf8"));
235
278
  return {};
236
279
  } catch {
237
280
  return {};
@@ -244,11 +287,16 @@ if (process.argv[1]?.includes("dashboard.mjs")) {
244
287
  const teamIdx = process.argv.indexOf("--team");
245
288
  const sessionName = sessionIdx !== -1 ? process.argv[sessionIdx + 1] : null;
246
289
  const teamName = teamIdx !== -1 ? process.argv[teamIdx + 1] : null;
247
- const intervalSec = parseInt(process.argv[process.argv.indexOf("--interval") + 1] || "2", 10);
290
+ const intervalSec = parseInt(
291
+ process.argv[process.argv.indexOf("--interval") + 1] || "2",
292
+ 10,
293
+ );
248
294
 
249
295
  const displayName = sessionName || teamName;
250
296
  if (!displayName) {
251
- console.error("사용법: node dashboard.mjs --session <세션이름> [--team <팀이름>] [--interval 2]");
297
+ console.error(
298
+ "사용법: node dashboard.mjs --session <세션이름> [--team <팀이름>] [--interval 2]",
299
+ );
252
300
  process.exit(1);
253
301
  }
254
302
 
@@ -2,8 +2,8 @@
2
2
  // Conductor 세션 lifecycle 이벤트를 JSONL 파일에 기록한다.
3
3
  // 기존 hub/server.mjs의 batch-events.jsonl(MCP 이벤트)과 독립. 공존.
4
4
 
5
- import { createWriteStream, mkdirSync } from 'node:fs';
6
- import { dirname } from 'node:path';
5
+ import { createWriteStream, mkdirSync } from "node:fs";
6
+ import { dirname } from "node:path";
7
7
 
8
8
  /**
9
9
  * JSONL event log 팩토리.
@@ -16,7 +16,7 @@ export function createEventLog(filePath, opts = {}) {
16
16
  const { sessionId } = opts;
17
17
 
18
18
  mkdirSync(dirname(filePath), { recursive: true });
19
- const stream = createWriteStream(filePath, { flags: 'a' });
19
+ const stream = createWriteStream(filePath, { flags: "a" });
20
20
 
21
21
  let closed = false;
22
22
  let pending = 0;
@@ -35,7 +35,9 @@ export function createEventLog(filePath, opts = {}) {
35
35
  ...data,
36
36
  };
37
37
  pending += 1;
38
- stream.write(JSON.stringify(entry) + '\n', () => { pending -= 1; });
38
+ stream.write(JSON.stringify(entry) + "\n", () => {
39
+ pending -= 1;
40
+ });
39
41
  }
40
42
 
41
43
  /**
@@ -45,9 +47,9 @@ export function createEventLog(filePath, opts = {}) {
45
47
  function flush() {
46
48
  if (closed) return Promise.resolve();
47
49
  return new Promise((resolve, reject) => {
48
- stream.once('error', reject);
49
- stream.write('', () => {
50
- stream.removeListener('error', reject);
50
+ stream.once("error", reject);
51
+ stream.write("", () => {
52
+ stream.removeListener("error", reject);
51
53
  resolve();
52
54
  });
53
55
  });
@@ -69,8 +71,14 @@ export function createEventLog(filePath, opts = {}) {
69
71
  append,
70
72
  flush,
71
73
  close,
72
- get filePath() { return filePath; },
73
- get pending() { return pending; },
74
- get closed() { return closed; },
74
+ get filePath() {
75
+ return filePath;
76
+ },
77
+ get pending() {
78
+ return pending;
79
+ },
80
+ get closed() {
81
+ return closed;
82
+ },
75
83
  });
76
84
  }