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,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+
2
3
  // scripts/test-lock.mjs — 테스트 러너 싱글톤 lockfile 가드
3
4
  //
4
5
  // npm test 동시 실행 방지. conductor 같은 child-spawn 테스트가
@@ -6,9 +7,9 @@
6
7
  //
7
8
  // 사용: node scripts/test-lock.mjs [-- ...node --test args]
8
9
 
9
- import { writeFileSync, readFileSync, unlinkSync, mkdirSync } from "node:fs";
10
- import { join } from "node:path";
11
10
  import { spawn } from "node:child_process";
11
+ import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
12
+ import { join } from "node:path";
12
13
 
13
14
  const LOCK_DIR = join(import.meta.dirname, "..", ".test-lock");
14
15
  const LOCK_FILE = join(LOCK_DIR, "pid.lock");
@@ -31,8 +32,12 @@ function acquireLock() {
31
32
  // Windows에서 process.kill(pid,0)이 git-bash PID를 못 잡음.
32
33
  // 단순하게: lockfile이 있고 STALE_THRESHOLD 이내면 거부.
33
34
  if (age >= 0 && age < STALE_THRESHOLD_MS) {
34
- console.error(`\x1b[31m✗ 테스트 이미 실행 중 (PID ${existing.pid}, ${Math.round(age / 1000)}초 전 시작)\x1b[0m`);
35
- console.error(` 동시 실행은 WT 메모리 폭발을 유발합니다. 기다리거나 PID를 kill하세요.`);
35
+ console.error(
36
+ `\x1b[31m✗ 테스트 이미 실행 (PID ${existing.pid}, ${Math.round(age / 1000)}초 전 시작)\x1b[0m`,
37
+ );
38
+ console.error(
39
+ ` 동시 실행은 WT 메모리 폭발을 유발합니다. 기다리거나 PID를 kill하세요.`,
40
+ );
36
41
  console.error(` 강제 해제: rm ${LOCK_FILE}`);
37
42
  process.exit(1);
38
43
  }
@@ -46,7 +51,9 @@ function releaseLock() {
46
51
  try {
47
52
  const lock = readLock();
48
53
  if (lock && lock.pid === process.pid) unlinkSync(LOCK_FILE);
49
- } catch { /* ignore */ }
54
+ } catch {
55
+ /* ignore */
56
+ }
50
57
  }
51
58
 
52
59
  // ── main ──
@@ -55,8 +62,14 @@ acquireLock();
55
62
 
56
63
  // cleanup on exit
57
64
  process.on("exit", releaseLock);
58
- process.on("SIGINT", () => { releaseLock(); process.exit(130); });
59
- process.on("SIGTERM", () => { releaseLock(); process.exit(143); });
65
+ process.on("SIGINT", () => {
66
+ releaseLock();
67
+ process.exit(130);
68
+ });
69
+ process.on("SIGTERM", () => {
70
+ releaseLock();
71
+ process.exit(143);
72
+ });
60
73
 
61
74
  // forward args after -- to node --test
62
75
  const args = process.argv.slice(2);
@@ -1,57 +1,61 @@
1
- #!/usr/bin/env node
2
- import test from "node:test";
3
- import assert from "node:assert/strict";
4
- import { spawnSync } from "node:child_process";
5
- import { dirname, resolve } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
-
8
- const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
9
- const PROJECT_ROOT = resolve(SCRIPT_DIR, "..");
10
-
11
- function runBash(command) {
12
- return spawnSync("bash", ["-lc", command], {
13
- cwd: PROJECT_ROOT,
14
- encoding: "utf8",
15
- env: {
16
- ...process.env,
17
- TFX_TEAM_NAME: '',
18
- TFX_TEAM_TASK_ID: '',
19
- TFX_TEAM_AGENT_NAME: '',
20
- TFX_TEAM_LEAD_NAME: '',
21
- TFX_HUB_URL: '',
22
- TMUX: '',
23
- }
24
- });
25
- }
26
-
27
- function out(result) {
28
- return `${result.stdout || ""}\n${result.stderr || ""}`;
29
- }
30
-
31
- test("gemini 모드에서는 no-claude-native 강제 치환이 적용되지 않는다", () => {
32
- const result = runBash(
33
- "TFX_CLI_MODE=gemini TFX_NO_CLAUDE_NATIVE=1 bash scripts/tfx-route.sh explore 'test-case'"
34
- );
35
-
36
- assert.equal(result.status, 0, out(result));
37
- assert.match(out(result), /ROUTE_TYPE=claude-native/, out(result));
38
- });
39
-
40
- test("auto 모드 + no-claude-native=1이면 explore가 codex로 치환된다", () => {
41
- const result = runBash(
42
- "TFX_CLI_MODE=auto TFX_NO_CLAUDE_NATIVE=1 CODEX_BIN=true bash scripts/tfx-route.sh explore 'test-case' minimal 5"
43
- );
44
-
45
- assert.equal(result.status, 0, out(result));
46
- assert.match(out(result), /TFX_NO_CLAUDE_NATIVE=1: explore -> codex/, out(result));
47
- assert.match(out(result), /type=codex|cli:\\s*codex/i, out(result));
48
- });
49
-
50
- test("TFX_NO_CLAUDE_NATIVE는 0/1 값만 허용한다", () => {
51
- const result = runBash(
52
- "TFX_NO_CLAUDE_NATIVE=2 bash scripts/tfx-route.sh explore 'test-case'"
53
- );
54
-
55
- assert.notEqual(result.status, 0, out(result));
56
- assert.match(out(result), /0 또는 1/, out(result));
57
- });
1
+ #!/usr/bin/env node
2
+ import assert from "node:assert/strict";
3
+ import { spawnSync } from "node:child_process";
4
+ import { dirname, resolve } from "node:path";
5
+ import test from "node:test";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
9
+ const PROJECT_ROOT = resolve(SCRIPT_DIR, "..");
10
+
11
+ function runBash(command) {
12
+ return spawnSync("bash", ["-lc", command], {
13
+ cwd: PROJECT_ROOT,
14
+ encoding: "utf8",
15
+ env: {
16
+ ...process.env,
17
+ TFX_TEAM_NAME: "",
18
+ TFX_TEAM_TASK_ID: "",
19
+ TFX_TEAM_AGENT_NAME: "",
20
+ TFX_TEAM_LEAD_NAME: "",
21
+ TFX_HUB_URL: "",
22
+ TMUX: "",
23
+ },
24
+ });
25
+ }
26
+
27
+ function out(result) {
28
+ return `${result.stdout || ""}\n${result.stderr || ""}`;
29
+ }
30
+
31
+ test("gemini 모드에서는 no-claude-native 강제 치환이 적용되지 않는다", () => {
32
+ const result = runBash(
33
+ "TFX_CLI_MODE=gemini TFX_NO_CLAUDE_NATIVE=1 bash scripts/tfx-route.sh explore 'test-case'",
34
+ );
35
+
36
+ assert.equal(result.status, 0, out(result));
37
+ assert.match(out(result), /ROUTE_TYPE=claude-native/, out(result));
38
+ });
39
+
40
+ test("auto 모드 + no-claude-native=1이면 explore가 codex로 치환된다", () => {
41
+ const result = runBash(
42
+ "TFX_CLI_MODE=auto TFX_NO_CLAUDE_NATIVE=1 CODEX_BIN=true bash scripts/tfx-route.sh explore 'test-case' minimal 5",
43
+ );
44
+
45
+ assert.equal(result.status, 0, out(result));
46
+ assert.match(
47
+ out(result),
48
+ /TFX_NO_CLAUDE_NATIVE=1: explore -> codex/,
49
+ out(result),
50
+ );
51
+ assert.match(out(result), /type=codex|cli:\\s*codex/i, out(result));
52
+ });
53
+
54
+ test("TFX_NO_CLAUDE_NATIVE는 0/1 값만 허용한다", () => {
55
+ const result = runBash(
56
+ "TFX_NO_CLAUDE_NATIVE=2 bash scripts/tfx-route.sh explore 'test-case'",
57
+ );
58
+
59
+ assert.notEqual(result.status, 0, out(result));
60
+ assert.match(out(result), /0 또는 1/, out(result));
61
+ });
@@ -1,96 +1,117 @@
1
- #!/usr/bin/env node
2
- // tfx-batch-stats.mjs v1.0 — batch-events.jsonl 소비자
3
- //
4
- // tfx-route-post.mjs가 기록한 AIMD 이벤트를 읽어서:
5
- // 1. 에이전트별 성공/실패/타임아웃 통계 집계
6
- // 2. AIMD(Additive Increase / Multiplicative Decrease) batch_size 계산
7
- //
8
- // 사용법:
9
- // node tfx-batch-stats.mjs stats [--recent] 에이전트별 통계 (--recent: 30분)
10
- // node tfx-batch-stats.mjs batch 현재 권장 batch_size
11
- // node tfx-batch-stats.mjs agent <name> 특정 에이전트 통계
12
-
13
- import { readFileSync } from "node:fs";
14
- import { join } from "node:path";
15
- import { homedir } from "node:os";
16
-
17
- const CACHE_DIR = join(homedir(), ".claude", "cache");
18
- const EVENTS_FILE = join(CACHE_DIR, "batch-events.jsonl");
19
-
20
- // AIMD 파라미터
21
- const AIMD_INITIAL = 3;
22
- const AIMD_MIN = 1;
23
- const AIMD_MAX = 10;
24
- const AIMD_INC = 1; // 성공 시 +1
25
- const AIMD_DEC = 0.5; // 실패 시 ×0.5
26
- const WINDOW_MS = 30 * 60 * 1000; // 30분 윈도우
27
-
28
- // ── 이벤트 읽기 ──
29
- export function readBatchEvents(opts = {}) {
30
- const { sinceMs = 0, agent = null } = opts;
31
- try {
32
- const lines = readFileSync(EVENTS_FILE, "utf-8").trim().split("\n").filter(Boolean);
33
- return lines
34
- .map((l) => { try { return JSON.parse(l); } catch { return null; } })
35
- .filter((e) => e && (!sinceMs || e.ts >= sinceMs) && (!agent || e.agent === agent));
36
- } catch {
37
- return [];
38
- }
39
- }
40
-
41
- // ── 에이전트별 통계 ──
42
- export function getAgentStats(opts = {}) {
43
- const events = readBatchEvents(opts);
44
- const stats = {};
45
-
46
- for (const ev of events) {
47
- if (!stats[ev.agent]) stats[ev.agent] = { success: 0, fail: 0, timeout: 0, total: 0 };
48
- const s = stats[ev.agent];
49
- if (ev.result === "success" || ev.result === "success_with_warnings") s.success++;
50
- else if (ev.result === "timeout") s.timeout++;
51
- else s.fail++;
52
- s.total++;
53
- }
54
-
55
- for (const s of Object.values(stats)) {
56
- s.successRate = s.total > 0 ? +(s.success / s.total).toFixed(2) : 0;
57
- }
58
-
59
- return { total: events.length, agents: stats };
60
- }
61
-
62
- // ── AIMD batch_size 계산 ──
63
- // 최근 윈도우 이벤트를 순회하며 성공 시 +1, 실패 시 ×0.5
64
- export function getAimdBatchSize() {
65
- const since = Date.now() - WINDOW_MS;
66
- const events = readBatchEvents({ sinceMs: since });
67
- if (events.length === 0) return AIMD_INITIAL;
68
-
69
- let batch = AIMD_INITIAL;
70
- for (const ev of events) {
71
- if (ev.result === "success" || ev.result === "success_with_warnings") {
72
- batch = Math.min(AIMD_MAX, batch + AIMD_INC);
73
- } else {
74
- batch = Math.max(AIMD_MIN, Math.floor(batch * AIMD_DEC));
75
- }
76
- }
77
- return batch;
78
- }
79
-
80
- // ── CLI 진입점 ──
81
- const scriptName = process.argv[1] || "";
82
- if (scriptName.endsWith("tfx-batch-stats.mjs")) {
83
- const cmd = process.argv[2] || "stats";
84
- const recent = process.argv.includes("--recent");
85
- const sinceMs = recent ? Date.now() - WINDOW_MS : 0;
86
-
87
- if (cmd === "batch") {
88
- console.log(JSON.stringify({ batchSize: getAimdBatchSize(), window: "30m" }));
89
- } else if (cmd === "agent") {
90
- const name = process.argv[3];
91
- if (!name) { console.error("에이전트명 필수: node tfx-batch-stats.mjs agent executor"); process.exit(1); }
92
- console.log(JSON.stringify(getAgentStats({ sinceMs, agent: name }), null, 2));
93
- } else {
94
- console.log(JSON.stringify(getAgentStats({ sinceMs }), null, 2));
95
- }
96
- }
1
+ #!/usr/bin/env node
2
+ // tfx-batch-stats.mjs v1.0 — batch-events.jsonl 소비자
3
+ //
4
+ // tfx-route-post.mjs가 기록한 AIMD 이벤트를 읽어서:
5
+ // 1. 에이전트별 성공/실패/타임아웃 통계 집계
6
+ // 2. AIMD(Additive Increase / Multiplicative Decrease) batch_size 계산
7
+ //
8
+ // 사용법:
9
+ // node tfx-batch-stats.mjs stats [--recent] 에이전트별 통계 (--recent: 30분)
10
+ // node tfx-batch-stats.mjs batch 현재 권장 batch_size
11
+ // node tfx-batch-stats.mjs agent <name> 특정 에이전트 통계
12
+
13
+ import { readFileSync } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import { join } from "node:path";
16
+
17
+ const CACHE_DIR = join(homedir(), ".claude", "cache");
18
+ const EVENTS_FILE = join(CACHE_DIR, "batch-events.jsonl");
19
+
20
+ // AIMD 파라미터
21
+ const AIMD_INITIAL = 3;
22
+ const AIMD_MIN = 1;
23
+ const AIMD_MAX = 10;
24
+ const AIMD_INC = 1; // 성공 시 +1
25
+ const AIMD_DEC = 0.5; // 실패 시 ×0.5
26
+ const WINDOW_MS = 30 * 60 * 1000; // 30분 윈도우
27
+
28
+ // ── 이벤트 읽기 ──
29
+ export function readBatchEvents(opts = {}) {
30
+ const { sinceMs = 0, agent = null } = opts;
31
+ try {
32
+ const lines = readFileSync(EVENTS_FILE, "utf-8")
33
+ .trim()
34
+ .split("\n")
35
+ .filter(Boolean);
36
+ return lines
37
+ .map((l) => {
38
+ try {
39
+ return JSON.parse(l);
40
+ } catch {
41
+ return null;
42
+ }
43
+ })
44
+ .filter(
45
+ (e) =>
46
+ e && (!sinceMs || e.ts >= sinceMs) && (!agent || e.agent === agent),
47
+ );
48
+ } catch {
49
+ return [];
50
+ }
51
+ }
52
+
53
+ // ── 에이전트별 통계 ──
54
+ export function getAgentStats(opts = {}) {
55
+ const events = readBatchEvents(opts);
56
+ const stats = {};
57
+
58
+ for (const ev of events) {
59
+ if (!stats[ev.agent])
60
+ stats[ev.agent] = { success: 0, fail: 0, timeout: 0, total: 0 };
61
+ const s = stats[ev.agent];
62
+ if (ev.result === "success" || ev.result === "success_with_warnings")
63
+ s.success++;
64
+ else if (ev.result === "timeout") s.timeout++;
65
+ else s.fail++;
66
+ s.total++;
67
+ }
68
+
69
+ for (const s of Object.values(stats)) {
70
+ s.successRate = s.total > 0 ? +(s.success / s.total).toFixed(2) : 0;
71
+ }
72
+
73
+ return { total: events.length, agents: stats };
74
+ }
75
+
76
+ // ── AIMD batch_size 계산 ──
77
+ // 최근 윈도우 이벤트를 순회하며 성공 시 +1, 실패 시 ×0.5
78
+ export function getAimdBatchSize() {
79
+ const since = Date.now() - WINDOW_MS;
80
+ const events = readBatchEvents({ sinceMs: since });
81
+ if (events.length === 0) return AIMD_INITIAL;
82
+
83
+ let batch = AIMD_INITIAL;
84
+ for (const ev of events) {
85
+ if (ev.result === "success" || ev.result === "success_with_warnings") {
86
+ batch = Math.min(AIMD_MAX, batch + AIMD_INC);
87
+ } else {
88
+ batch = Math.max(AIMD_MIN, Math.floor(batch * AIMD_DEC));
89
+ }
90
+ }
91
+ return batch;
92
+ }
93
+
94
+ // ── CLI 진입점 ──
95
+ const scriptName = process.argv[1] || "";
96
+ if (scriptName.endsWith("tfx-batch-stats.mjs")) {
97
+ const cmd = process.argv[2] || "stats";
98
+ const recent = process.argv.includes("--recent");
99
+ const sinceMs = recent ? Date.now() - WINDOW_MS : 0;
100
+
101
+ if (cmd === "batch") {
102
+ console.log(
103
+ JSON.stringify({ batchSize: getAimdBatchSize(), window: "30m" }),
104
+ );
105
+ } else if (cmd === "agent") {
106
+ const name = process.argv[3];
107
+ if (!name) {
108
+ console.error("에이전트명 필수: node tfx-batch-stats.mjs agent executor");
109
+ process.exit(1);
110
+ }
111
+ console.log(
112
+ JSON.stringify(getAgentStats({ sinceMs, agent: name }), null, 2),
113
+ );
114
+ } else {
115
+ console.log(JSON.stringify(getAgentStats({ sinceMs }), null, 2));
116
+ }
117
+ }
@@ -9,7 +9,7 @@
9
9
  * 자동 만료: 30분
10
10
  */
11
11
 
12
- import { writeFileSync, existsSync, readFileSync } from "node:fs";
12
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
13
13
  import { tmpdir } from "node:os";
14
14
  import { join } from "node:path";
15
15
 
@@ -42,15 +42,22 @@ async function main() {
42
42
 
43
43
  // 모든 tfx CLI 라우팅 스킬에 gate 적용
44
44
  const TFX_ROUTING_SKILLS = new Set([
45
- "tfx-multi", "tfx-team", "tfx-auto", "tfx-auto-codex",
46
- "tfx-codex", "tfx-gemini", "tfx-autoresearch",
45
+ "tfx-multi",
46
+ "tfx-team",
47
+ "tfx-auto",
48
+ "tfx-auto-codex",
49
+ "tfx-codex",
50
+ "tfx-gemini",
51
+ "tfx-autoresearch",
47
52
  ]);
48
53
 
49
54
  if (TFX_ROUTING_SKILLS.has(skill)) {
50
55
  // 활성화: 상태 파일 생성/갱신
56
+ // ppid = Claude Code 세션 PID (훅은 Claude Code의 자식 프로세스)
51
57
  const state = {
52
58
  active: true,
53
59
  activatedAt: Date.now(),
60
+ ownerPid: process.ppid,
54
61
  dispatched: false,
55
62
  nativeWorkCalls: 0,
56
63
  nativeWorkCallsSinceDispatch: 0,
@@ -64,7 +71,7 @@ async function main() {
64
71
  hookEventName: "PreToolUse",
65
72
  additionalContext:
66
73
  "[tfx-multi] gate 활성화됨. CLI 작업은 headless로 dispatch 필수:\n" +
67
- 'Bash("tfx multi --teammate-mode headless --auto-attach --dashboard --assign \'codex:프롬프트:역할\' --timeout 600")',
74
+ "Bash(\"tfx multi --teammate-mode headless --auto-attach --dashboard --assign 'codex:프롬프트:역할' --timeout 600\")",
68
75
  },
69
76
  }),
70
77
  );
@@ -13,9 +13,17 @@
13
13
  // 6. CLI 이슈 자동 수집
14
14
  // 7. 구조화된 결과 출력 (=== TFX-ROUTE RESULT ===)
15
15
 
16
- import { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
17
- import { join } from "path";
16
+ import {
17
+ appendFileSync,
18
+ existsSync,
19
+ mkdirSync,
20
+ readdirSync,
21
+ readFileSync,
22
+ statSync,
23
+ writeFileSync,
24
+ } from "fs";
18
25
  import { homedir } from "os";
26
+ import { join } from "path";
19
27
 
20
28
  const HOME = homedir();
21
29
  const CACHE_DIR = join(HOME, ".claude", "cache");
@@ -171,7 +179,10 @@ function extractCodexSessionId(rawOutput, stderrContent = "") {
171
179
 
172
180
  function appendCodexResumeHint(output, rawOutput, stderrContent = "") {
173
181
  const normalizedOutput = String(output || "").trim();
174
- if (/Codex session ID:/i.test(normalizedOutput) || /codex resume\s+/i.test(normalizedOutput)) {
182
+ if (
183
+ /Codex session ID:/i.test(normalizedOutput) ||
184
+ /codex resume\s+/i.test(normalizedOutput)
185
+ ) {
175
186
  return normalizedOutput;
176
187
  }
177
188
 
@@ -184,7 +195,11 @@ function appendCodexResumeHint(output, rawOutput, stderrContent = "") {
184
195
  return normalizedOutput ? `${normalizedOutput}\n\n${hint}` : hint;
185
196
  }
186
197
 
187
- function prepareCliOutput(rawOutput, cliType, { cleanTui = true, stderrContent = "" } = {}) {
198
+ function prepareCliOutput(
199
+ rawOutput,
200
+ cliType,
201
+ { cleanTui = true, stderrContent = "" } = {},
202
+ ) {
188
203
  let prepared = cliType === "codex" ? filterCodexOutput(rawOutput) : rawOutput;
189
204
  if (cleanTui && process.env.TFX_CLEAN_TUI !== "0") {
190
205
  prepared = cleanTuiArtifacts(prepared, cliType);
@@ -214,7 +229,9 @@ function cleanTuiArtifacts(output, cliType) {
214
229
  .replace(/^\s*codex\s*$/gm, "")
215
230
  .replace(/^[^\S\n]*[›❯]\s*Applied.*$/gm, "");
216
231
  } else if (normalizedCliType.startsWith("gemini")) {
217
- cleaned = cleaned.replace(/^[^\S\n]*[╭╮╰╯│─═].*$/gm, "").replace(/^[^\S\n]*>\s*$/gm, "");
232
+ cleaned = cleaned
233
+ .replace(/^[^\S\n]*[╭╮╰╯│─═].*$/gm, "")
234
+ .replace(/^[^\S\n]*>\s*$/gm, "");
218
235
  } else if (normalizedCliType.startsWith("claude")) {
219
236
  cleaned = cleaned.replace(/^[^\S\n]*[━─]{5,}.*$/gm, "");
220
237
  }
@@ -285,7 +302,10 @@ function recordBatchEvent(result, agent) {
285
302
  const eventsFile = join(CACHE_DIR, "batch-events.jsonl");
286
303
  try {
287
304
  mkdirSync(CACHE_DIR, { recursive: true });
288
- appendFileSync(eventsFile, JSON.stringify({ ts: Date.now(), agent, result }) + "\n");
305
+ appendFileSync(
306
+ eventsFile,
307
+ JSON.stringify({ ts: Date.now(), agent, result }) + "\n",
308
+ );
289
309
 
290
310
  // 자동 회전: 200줄 초과 시 최근 100줄 유지
291
311
  const content = readFileSync(eventsFile, "utf-8").trim();
@@ -301,12 +321,42 @@ function trackCliIssue(cliType, agent, stderrText, exitCode) {
301
321
  if (!stderrText && exitCode === 0) return;
302
322
 
303
323
  const patterns = [
304
- { regex: /sandbox image.*missing/i, pattern: "sandbox_missing", msg: "Docker sandbox image not found", severity: "warn" },
305
- { regex: /rate.limit|429|too many requests/i, pattern: "rate_limit", msg: "API rate limit exceeded", severity: "warn" },
306
- { regex: /ECONNREFUSED|ENOTFOUND|network/i, pattern: "network_error", msg: "Network connection failed", severity: "error" },
307
- { regex: /deprecated/i, pattern: "deprecated_flag", msg: "Deprecated flag/feature detected", severity: "warn" },
308
- { regex: /API_KEY.*not.set|auth.*fail|unauthorized|401/i, pattern: "auth_error", msg: "Authentication failed", severity: "error" },
309
- { regex: /ENOMEM|out of memory|heap/i, pattern: "oom", msg: "Out of memory", severity: "error" },
324
+ {
325
+ regex: /sandbox image.*missing/i,
326
+ pattern: "sandbox_missing",
327
+ msg: "Docker sandbox image not found",
328
+ severity: "warn",
329
+ },
330
+ {
331
+ regex: /rate.limit|429|too many requests/i,
332
+ pattern: "rate_limit",
333
+ msg: "API rate limit exceeded",
334
+ severity: "warn",
335
+ },
336
+ {
337
+ regex: /ECONNREFUSED|ENOTFOUND|network/i,
338
+ pattern: "network_error",
339
+ msg: "Network connection failed",
340
+ severity: "error",
341
+ },
342
+ {
343
+ regex: /deprecated/i,
344
+ pattern: "deprecated_flag",
345
+ msg: "Deprecated flag/feature detected",
346
+ severity: "warn",
347
+ },
348
+ {
349
+ regex: /API_KEY.*not.set|auth.*fail|unauthorized|401/i,
350
+ pattern: "auth_error",
351
+ msg: "Authentication failed",
352
+ severity: "error",
353
+ },
354
+ {
355
+ regex: /ENOMEM|out of memory|heap/i,
356
+ pattern: "oom",
357
+ msg: "Out of memory",
358
+ severity: "error",
359
+ },
310
360
  ];
311
361
 
312
362
  let matched = null;
@@ -318,7 +368,11 @@ function trackCliIssue(cliType, agent, stderrText, exitCode) {
318
368
  }
319
369
 
320
370
  if (!matched && exitCode !== 0 && exitCode !== 124) {
321
- matched = { pattern: "unknown_error", msg: `Exit code ${exitCode}`, severity: "warn" };
371
+ matched = {
372
+ pattern: "unknown_error",
373
+ msg: `Exit code ${exitCode}`,
374
+ severity: "warn",
375
+ };
322
376
  }
323
377
 
324
378
  if (!matched) return;
@@ -329,21 +383,30 @@ function trackCliIssue(cliType, agent, stderrText, exitCode) {
329
383
 
330
384
  // 중복 방지: 같은 패턴+cli가 최근 5분 내 기록됐으면 건너뜀
331
385
  if (existsSync(issuesFile)) {
332
- const lines = readFileSync(issuesFile, "utf-8").trim().split("\n").slice(-5);
386
+ const lines = readFileSync(issuesFile, "utf-8")
387
+ .trim()
388
+ .split("\n")
389
+ .slice(-5);
333
390
  const now = Date.now();
334
391
  for (const line of lines) {
335
392
  try {
336
393
  const entry = JSON.parse(line);
337
- if (entry.pattern === matched.pattern && entry.cli === cliType && now - entry.ts < 300000) return;
394
+ if (
395
+ entry.pattern === matched.pattern &&
396
+ entry.cli === cliType &&
397
+ now - entry.ts < 300000
398
+ )
399
+ return;
338
400
  } catch {}
339
401
  }
340
402
  }
341
403
 
342
404
  const snippet = stderrText.substring(0, 200).replace(/\n/g, " ");
343
405
 
344
- const retryCount = (matched.pattern === "rate_limit" && cliType === "gemini")
345
- ? parseInt(process.env.TFX_GEMINI_429_RETRIES || "0", 10)
346
- : undefined;
406
+ const retryCount =
407
+ matched.pattern === "rate_limit" && cliType === "gemini"
408
+ ? parseInt(process.env.TFX_GEMINI_429_RETRIES || "0", 10)
409
+ : undefined;
347
410
 
348
411
  const issueEntry = {
349
412
  ts: Date.now(),
@@ -440,7 +503,8 @@ function main() {
440
503
  if (exitCode === 0) accumulateTokens(cliType, tokens);
441
504
 
442
505
  // 5. AIMD 배치 이벤트
443
- const aimdResult = exitCode === 0 ? "success" : exitCode === 124 ? "timeout" : "failed";
506
+ const aimdResult =
507
+ exitCode === 0 ? "success" : exitCode === 124 ? "timeout" : "failed";
444
508
  recordBatchEvent(aimdResult, agent);
445
509
 
446
510
  // 6. CLI 이슈 추적
@@ -462,7 +526,9 @@ function main() {
462
526
  if (exitCode === 0) {
463
527
  if (stderrContent) {
464
528
  console.log("status: success_with_warnings");
465
- console.log(`warnings: ${stderrContent.split("\n").slice(0, 3).join(" ")}`);
529
+ console.log(
530
+ `warnings: ${stderrContent.split("\n").slice(0, 3).join(" ")}`,
531
+ );
466
532
  } else {
467
533
  console.log("status: success");
468
534
  }
@@ -498,6 +564,7 @@ function main() {
498
564
  }
499
565
 
500
566
  import { fileURLToPath } from "url";
567
+
501
568
  if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
502
569
  main();
503
570
  }