triflux 10.0.0 → 10.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/CLAUDE.md +171 -0
  2. package/README.md +32 -15
  3. package/bin/triflux.mjs +62 -5
  4. package/hooks/agent-route-guard.mjs +109 -0
  5. package/hooks/cross-review-tracker.mjs +122 -0
  6. package/hooks/error-context.mjs +148 -0
  7. package/hooks/hook-adaptive-collector.mjs +86 -0
  8. package/hooks/hook-manager.mjs +365 -0
  9. package/hooks/hook-orchestrator.mjs +312 -0
  10. package/hooks/hook-registry.json +246 -0
  11. package/hooks/hooks.json +89 -0
  12. package/hooks/keyword-rules.json +574 -0
  13. package/hooks/lib/resolve-root.mjs +59 -0
  14. package/hooks/mcp-config-watcher.mjs +80 -0
  15. package/hooks/pipeline-stop.mjs +76 -0
  16. package/hooks/safety-guard.mjs +169 -0
  17. package/hooks/subagent-verifier.mjs +80 -0
  18. package/hub/account-broker.mjs +251 -0
  19. package/hub/adaptive-diagnostic.mjs +323 -0
  20. package/hub/adaptive-inject.mjs +186 -0
  21. package/hub/adaptive-memory.mjs +163 -0
  22. package/hub/adaptive.mjs +143 -0
  23. package/hub/assign-callbacks.mjs +133 -0
  24. package/hub/bridge.mjs +799 -0
  25. package/hub/cli-adapter-base.mjs +280 -0
  26. package/hub/codex-adapter.mjs +199 -0
  27. package/hub/codex-compat.mjs +11 -0
  28. package/hub/codex-preflight.mjs +166 -0
  29. package/hub/delegator/contracts.mjs +37 -0
  30. package/hub/delegator/index.mjs +14 -0
  31. package/hub/delegator/schema/delegator-tools.schema.json +250 -0
  32. package/hub/delegator/service.mjs +307 -0
  33. package/hub/delegator/tool-definitions.mjs +35 -0
  34. package/hub/fullcycle.mjs +96 -0
  35. package/hub/gemini-adapter.mjs +180 -0
  36. package/hub/hitl.mjs +143 -0
  37. package/hub/intent.mjs +193 -0
  38. package/hub/lib/cache-guard.mjs +114 -0
  39. package/hub/lib/known-errors.json +72 -0
  40. package/hub/lib/memory-store.mjs +748 -0
  41. package/hub/lib/process-utils.mjs +361 -0
  42. package/hub/lib/ssh-command.mjs +211 -0
  43. package/hub/lib/ssh-retry.mjs +59 -0
  44. package/hub/lib/uuidv7.mjs +44 -0
  45. package/hub/memory-doctor.mjs +480 -0
  46. package/hub/middleware/request-logger.mjs +161 -0
  47. package/hub/paths.mjs +30 -0
  48. package/hub/pipe.mjs +664 -0
  49. package/hub/pipeline/gates/confidence.mjs +56 -0
  50. package/hub/pipeline/gates/consensus.mjs +94 -0
  51. package/hub/pipeline/gates/index.mjs +5 -0
  52. package/hub/pipeline/gates/selfcheck.mjs +82 -0
  53. package/hub/pipeline/index.mjs +318 -0
  54. package/hub/pipeline/state.mjs +191 -0
  55. package/hub/pipeline/transitions.mjs +124 -0
  56. package/hub/platform.mjs +225 -0
  57. package/hub/public/dashboard.html +355 -0
  58. package/hub/public/tray-icon.ico +0 -0
  59. package/hub/public/tray-icon.png +0 -0
  60. package/hub/quality/deslop.mjs +253 -0
  61. package/hub/reflexion.mjs +372 -0
  62. package/hub/research.mjs +146 -0
  63. package/hub/router.mjs +791 -0
  64. package/hub/routing/complexity.mjs +166 -0
  65. package/hub/routing/index.mjs +117 -0
  66. package/hub/routing/q-learning.mjs +336 -0
  67. package/hub/schema.sql +148 -0
  68. package/hub/server.mjs +1264 -0
  69. package/hub/session-fingerprint.mjs +352 -0
  70. package/hub/state.mjs +258 -0
  71. package/hub/store-adapter.mjs +118 -0
  72. package/hub/store.mjs +857 -0
  73. package/hub/team/agent-map.json +11 -0
  74. package/hub/team/ansi.mjs +379 -0
  75. package/hub/team/backend.mjs +90 -0
  76. package/hub/team/cli/commands/attach.mjs +37 -0
  77. package/hub/team/cli/commands/control.mjs +43 -0
  78. package/hub/team/cli/commands/debug.mjs +74 -0
  79. package/hub/team/cli/commands/focus.mjs +53 -0
  80. package/hub/team/cli/commands/interrupt.mjs +36 -0
  81. package/hub/team/cli/commands/kill.mjs +37 -0
  82. package/hub/team/cli/commands/list.mjs +24 -0
  83. package/hub/team/cli/commands/send.mjs +37 -0
  84. package/hub/team/cli/commands/start/index.mjs +106 -0
  85. package/hub/team/cli/commands/start/parse-args.mjs +130 -0
  86. package/hub/team/cli/commands/start/start-headless.mjs +109 -0
  87. package/hub/team/cli/commands/start/start-in-process.mjs +40 -0
  88. package/hub/team/cli/commands/start/start-mux.mjs +73 -0
  89. package/hub/team/cli/commands/start/start-wt.mjs +69 -0
  90. package/hub/team/cli/commands/status.mjs +87 -0
  91. package/hub/team/cli/commands/stop.mjs +31 -0
  92. package/hub/team/cli/commands/task.mjs +30 -0
  93. package/hub/team/cli/commands/tasks.mjs +13 -0
  94. package/hub/team/cli/help.mjs +42 -0
  95. package/hub/team/cli/index.mjs +41 -0
  96. package/hub/team/cli/manifest.mjs +29 -0
  97. package/hub/team/cli/render.mjs +30 -0
  98. package/hub/team/cli/services/attach-fallback.mjs +54 -0
  99. package/hub/team/cli/services/hub-client.mjs +227 -0
  100. package/hub/team/cli/services/member-selector.mjs +30 -0
  101. package/hub/team/cli/services/native-control.mjs +117 -0
  102. package/hub/team/cli/services/runtime-mode.mjs +62 -0
  103. package/hub/team/cli/services/state-store.mjs +48 -0
  104. package/hub/team/cli/services/task-model.mjs +30 -0
  105. package/hub/team/conductor-mesh-bridge.mjs +121 -0
  106. package/hub/team/conductor.mjs +671 -0
  107. package/hub/team/dashboard-anchor.mjs +14 -0
  108. package/hub/team/dashboard-layout.mjs +33 -0
  109. package/hub/team/dashboard-open.mjs +153 -0
  110. package/hub/team/dashboard.mjs +274 -0
  111. package/hub/team/event-log.mjs +76 -0
  112. package/hub/team/handoff.mjs +303 -0
  113. package/hub/team/headless.mjs +1156 -0
  114. package/hub/team/health-probe.mjs +272 -0
  115. package/hub/team/launcher-template.mjs +95 -0
  116. package/hub/team/lead-control.mjs +104 -0
  117. package/hub/team/native-supervisor.mjs +392 -0
  118. package/hub/team/native.mjs +649 -0
  119. package/hub/team/nativeProxy.mjs +688 -0
  120. package/hub/team/notify.mjs +293 -0
  121. package/hub/team/orchestrator.mjs +161 -0
  122. package/hub/team/pane.mjs +153 -0
  123. package/hub/team/process-cleanup.mjs +342 -0
  124. package/hub/team/psmux.mjs +1354 -0
  125. package/hub/team/remote-probe.mjs +276 -0
  126. package/hub/team/remote-session.mjs +299 -0
  127. package/hub/team/remote-watcher.mjs +478 -0
  128. package/hub/team/routing.mjs +223 -0
  129. package/hub/team/session-sync.mjs +169 -0
  130. package/hub/team/session.mjs +611 -0
  131. package/hub/team/shared.mjs +13 -0
  132. package/hub/team/staleState.mjs +361 -0
  133. package/hub/team/swarm-hypervisor.mjs +589 -0
  134. package/hub/team/swarm-locks.mjs +204 -0
  135. package/hub/team/swarm-planner.mjs +260 -0
  136. package/hub/team/swarm-reconciler.mjs +137 -0
  137. package/hub/team/tui-lite.mjs +380 -0
  138. package/hub/team/tui-remote-adapter.mjs +393 -0
  139. package/hub/team/tui-viewer.mjs +463 -0
  140. package/hub/team/tui.mjs +1449 -0
  141. package/hub/team/worktree-lifecycle.mjs +193 -0
  142. package/hub/team/wt-manager.mjs +407 -0
  143. package/hub/team/wt-templates.json +43 -0
  144. package/hub/team-bridge.mjs +27 -0
  145. package/hub/token-mode.mjs +224 -0
  146. package/hub/tools.mjs +636 -0
  147. package/hub/tray.mjs +376 -0
  148. package/hub/workers/claude-worker.mjs +475 -0
  149. package/hub/workers/codex-mcp.mjs +507 -0
  150. package/hub/workers/delegator-mcp.mjs +1076 -0
  151. package/hub/workers/factory.mjs +21 -0
  152. package/hub/workers/gemini-worker.mjs +374 -0
  153. package/hub/workers/interface.mjs +52 -0
  154. package/hub/workers/worker-utils.mjs +104 -0
  155. package/hud/colors.mjs +88 -0
  156. package/hud/constants.mjs +88 -0
  157. package/hud/context-monitor.mjs +403 -0
  158. package/hud/hud-qos-status.mjs +210 -0
  159. package/hud/providers/claude.mjs +314 -0
  160. package/hud/providers/codex.mjs +151 -0
  161. package/hud/providers/gemini.mjs +320 -0
  162. package/hud/renderers.mjs +442 -0
  163. package/hud/terminal.mjs +140 -0
  164. package/hud/utils.mjs +313 -0
  165. package/mesh/index.mjs +63 -0
  166. package/mesh/mesh-budget.mjs +128 -0
  167. package/mesh/mesh-heartbeat.mjs +100 -0
  168. package/mesh/mesh-protocol.mjs +96 -0
  169. package/mesh/mesh-queue.mjs +165 -0
  170. package/mesh/mesh-registry.mjs +78 -0
  171. package/mesh/mesh-router.mjs +76 -0
  172. package/package.json +8 -1
  173. package/references/hosts.json +33 -0
  174. package/scripts/__tests__/gen-skill-docs.test.mjs +87 -0
  175. package/scripts/__tests__/keyword-detector.test.mjs +234 -0
  176. package/scripts/__tests__/mcp-guard-engine.test.mjs +118 -0
  177. package/scripts/__tests__/remote-spawn-transfer.test.mjs +117 -0
  178. package/scripts/__tests__/remote-spawn.test.mjs +92 -0
  179. package/scripts/__tests__/skill-template.test.mjs +193 -0
  180. package/scripts/__tests__/smoke.test.mjs +34 -0
  181. package/scripts/cache-buildup.mjs +30 -0
  182. package/scripts/cache-doctor.mjs +149 -0
  183. package/scripts/cache-warmup.mjs +557 -0
  184. package/scripts/claudemd-sync.mjs +148 -0
  185. package/scripts/cli-route.sh +3 -0
  186. package/scripts/completions/tfx.bash +47 -0
  187. package/scripts/completions/tfx.fish +44 -0
  188. package/scripts/completions/tfx.zsh +83 -0
  189. package/scripts/cross-review-gate.mjs +126 -0
  190. package/scripts/cross-review-tracker.mjs +238 -0
  191. package/scripts/gen-skill-docs.mjs +111 -0
  192. package/scripts/headless-guard-fast.sh +21 -0
  193. package/scripts/headless-guard.mjs +360 -0
  194. package/scripts/hub-ensure.mjs +120 -0
  195. package/scripts/keyword-detector.mjs +272 -0
  196. package/scripts/keyword-rules-expander.mjs +521 -0
  197. package/scripts/lib/claudemd-scanner.mjs +218 -0
  198. package/scripts/lib/context.mjs +67 -0
  199. package/scripts/lib/cross-review-utils.mjs +51 -0
  200. package/scripts/lib/env-probe.mjs +241 -0
  201. package/scripts/lib/gemini-profiles.mjs +85 -0
  202. package/scripts/lib/handoff.mjs +171 -0
  203. package/scripts/lib/hook-utils.mjs +14 -0
  204. package/scripts/lib/keyword-rules.mjs +166 -0
  205. package/scripts/lib/logger.mjs +105 -0
  206. package/scripts/lib/mcp-filter.mjs +739 -0
  207. package/scripts/lib/mcp-guard-engine.mjs +954 -0
  208. package/scripts/lib/mcp-manifest.mjs +79 -0
  209. package/scripts/lib/mcp-server-catalog.mjs +118 -0
  210. package/scripts/lib/psmux-info.mjs +119 -0
  211. package/scripts/lib/remote-spawn-transfer.mjs +196 -0
  212. package/scripts/lib/skill-template.mjs +326 -0
  213. package/scripts/mcp-check.mjs +237 -0
  214. package/scripts/mcp-cleanup.ps1 +17 -0
  215. package/scripts/mcp-gateway-config.mjs +207 -0
  216. package/scripts/mcp-gateway-ensure.mjs +85 -0
  217. package/scripts/mcp-gateway-integration-test.mjs +228 -0
  218. package/scripts/mcp-gateway-start.mjs +226 -0
  219. package/scripts/mcp-gateway-start.ps1 +141 -0
  220. package/scripts/mcp-gateway-verify.mjs +77 -0
  221. package/scripts/mcp-safety-guard.mjs +44 -0
  222. package/scripts/notion-read.mjs +556 -0
  223. package/scripts/pack.mjs +295 -0
  224. package/scripts/preflight-cache.mjs +69 -0
  225. package/scripts/preinstall.mjs +96 -0
  226. package/scripts/remote-spawn.mjs +1376 -0
  227. package/scripts/run.cjs +79 -0
  228. package/scripts/session-spawn-helper.mjs +185 -0
  229. package/scripts/setup.mjs +1178 -0
  230. package/scripts/test-lock.mjs +71 -0
  231. package/scripts/test-tfx-route-no-claude-native.mjs +57 -0
  232. package/scripts/tfx-batch-stats.mjs +96 -0
  233. package/scripts/tfx-gate-activate.mjs +89 -0
  234. package/scripts/tfx-route-post.mjs +505 -0
  235. package/scripts/tfx-route-worker.mjs +223 -0
  236. package/scripts/tfx-route.sh +2014 -0
  237. package/scripts/tmp-cleanup.mjs +103 -0
  238. package/scripts/token-snapshot.mjs +575 -0
  239. package/skills/tfx-auto/SKILL.md.tmpl +2 -3
  240. package/skills/tfx-autoresearch/SKILL.md +6 -5
  241. package/skills/tfx-codex/SKILL.md.tmpl +2 -3
  242. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +33 -0
  243. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +42 -0
  244. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +11 -0
  245. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +87 -0
  246. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +35 -0
  247. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +275 -0
  248. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +56 -0
  249. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +5 -0
  250. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +11 -0
  251. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +92 -0
  252. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +71 -0
  253. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +264 -0
  254. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +113 -0
  255. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +5 -0
  256. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +32 -0
  257. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +9 -0
  258. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +96 -0
  259. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +38 -0
  260. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +151 -0
  261. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +51 -0
  262. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +5 -0
  263. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +9 -0
  264. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +127 -0
  265. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +57 -0
  266. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +129 -0
  267. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +84 -0
  268. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +5 -0
  269. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +27 -0
  270. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +8 -0
  271. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +98 -0
  272. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +65 -0
  273. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +123 -0
  274. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +66 -0
  275. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +5 -0
  276. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +8 -0
  277. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +88 -0
  278. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +40 -0
  279. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +130 -0
  280. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +61 -0
  281. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +5 -0
  282. package/skills/tfx-deep-interview/SKILL.md +1 -2
  283. package/skills/tfx-plan/SKILL.md.tmpl +2 -3
  284. package/skills/tfx-psmux-rules/SKILL.md +11 -2
  285. package/skills/tfx-qa/SKILL.md.tmpl +2 -3
  286. package/skills/tfx-remote-spawn/SKILL.md +8 -11
  287. package/skills/tfx-research/SKILL.md.tmpl +2 -3
  288. package/skills/tfx-review/SKILL.md.tmpl +2 -3
  289. package/skills/tfx-workspace/async-tests/run-tests.sh +203 -0
  290. package/skills/tfx-workspace/evals/evals.json +79 -0
  291. package/skills/tfx-workspace/iteration-1/benchmark.json +162 -0
  292. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +11 -0
  293. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +9 -0
  294. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +154 -0
  295. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +5 -0
  296. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +9 -0
  297. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +126 -0
  298. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +5 -0
  299. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +11 -0
  300. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +9 -0
  301. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +119 -0
  302. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +5 -0
  303. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +9 -0
  304. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +115 -0
  305. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +5 -0
  306. package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +10 -0
  307. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +8 -0
  308. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +86 -0
  309. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +5 -0
  310. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +8 -0
  311. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +81 -0
  312. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +5 -0
  313. package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +12 -0
  314. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +10 -0
  315. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +316 -0
  316. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +5 -0
  317. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +10 -0
  318. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +352 -0
  319. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +5 -0
  320. package/skills/tfx-workspace/iteration-1/review.html +1325 -0
  321. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +12 -0
  322. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +10 -0
  323. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +97 -0
  324. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +5 -0
  325. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +10 -0
  326. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +94 -0
  327. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +5 -0
  328. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +12 -0
  329. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +10 -0
  330. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +209 -0
  331. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +5 -0
  332. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +10 -0
  333. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +193 -0
  334. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +5 -0
  335. package/skills/tfx-workspace/iteration-2/benchmark.json +62 -0
  336. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +13 -0
  337. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +11 -0
  338. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +382 -0
  339. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +5 -0
  340. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +11 -0
  341. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +333 -0
  342. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +5 -0
  343. package/skills/tfx-workspace/iteration-2/review.html +1325 -0
  344. package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +217 -0
  345. package/skills/{tfx-auto-codex/SKILL.md.tmpl → tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md} +3 -31
  346. package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +65 -0
  347. package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +94 -0
  348. package/skills/{tfx-gemini/SKILL.md.tmpl → tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md} +6 -14
  349. package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +133 -0
  350. package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +426 -0
  351. package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +101 -0
  352. package/skills/merge-worktree/SKILL.md.tmpl +0 -144
  353. package/skills/shared/arguments-processing.md +0 -2
  354. package/skills/shared/mandatory-rules.md +0 -6
  355. package/skills/shared/telemetry-segment.md +0 -6
  356. package/skills/star-prompt/SKILL.md.tmpl +0 -122
  357. package/skills/tfx-analysis/SKILL.md.tmpl +0 -106
  358. package/skills/tfx-analysis/skill.json +0 -11
  359. package/skills/tfx-auto/skill.json +0 -26
  360. package/skills/tfx-auto-codex/skill.json +0 -8
  361. package/skills/tfx-autopilot/SKILL.md.tmpl +0 -115
  362. package/skills/tfx-autopilot/skill.json +0 -10
  363. package/skills/tfx-autoresearch/SKILL.md.tmpl +0 -135
  364. package/skills/tfx-autoresearch/skill.json +0 -14
  365. package/skills/tfx-autoroute/SKILL.md.tmpl +0 -188
  366. package/skills/tfx-autoroute/skill.json +0 -12
  367. package/skills/tfx-codex/skill.json +0 -8
  368. package/skills/tfx-codex-swarm/SKILL.md.tmpl +0 -16
  369. package/skills/tfx-codex-swarm/skill.json +0 -5
  370. package/skills/tfx-consensus/SKILL.md.tmpl +0 -145
  371. package/skills/tfx-consensus/skill.json +0 -8
  372. package/skills/tfx-debate/SKILL.md.tmpl +0 -191
  373. package/skills/tfx-debate/skill.json +0 -12
  374. package/skills/tfx-deep-analysis/SKILL.md.tmpl +0 -227
  375. package/skills/tfx-deep-analysis/skill.json +0 -10
  376. package/skills/tfx-deep-interview/SKILL.md.tmpl +0 -203
  377. package/skills/tfx-deep-interview/skill.json +0 -12
  378. package/skills/tfx-deep-plan/SKILL.md.tmpl +0 -281
  379. package/skills/tfx-deep-plan/skill.json +0 -13
  380. package/skills/tfx-deep-qa/SKILL.md.tmpl +0 -164
  381. package/skills/tfx-deep-qa/skill.json +0 -11
  382. package/skills/tfx-deep-research/SKILL.md.tmpl +0 -216
  383. package/skills/tfx-deep-research/skill.json +0 -14
  384. package/skills/tfx-deep-review/SKILL.md.tmpl +0 -178
  385. package/skills/tfx-deep-review/skill.json +0 -12
  386. package/skills/tfx-doctor/SKILL.md.tmpl +0 -172
  387. package/skills/tfx-doctor/skill.json +0 -8
  388. package/skills/tfx-find/skill.json +0 -12
  389. package/skills/tfx-forge/SKILL.md.tmpl +0 -187
  390. package/skills/tfx-forge/skill.json +0 -12
  391. package/skills/tfx-fullcycle/SKILL.md.tmpl +0 -285
  392. package/skills/tfx-fullcycle/skill.json +0 -11
  393. package/skills/tfx-gemini/skill.json +0 -8
  394. package/skills/tfx-hooks/SKILL.md.tmpl +0 -216
  395. package/skills/tfx-hooks/skill.json +0 -8
  396. package/skills/tfx-hub/SKILL.md.tmpl +0 -212
  397. package/skills/tfx-hub/skill.json +0 -8
  398. package/skills/tfx-index/skill.json +0 -11
  399. package/skills/tfx-interview/SKILL.md.tmpl +0 -284
  400. package/skills/tfx-interview/skill.json +0 -12
  401. package/skills/tfx-multi/SKILL.md.tmpl +0 -183
  402. package/skills/tfx-multi/skill.json +0 -8
  403. package/skills/tfx-panel/SKILL.md.tmpl +0 -188
  404. package/skills/tfx-panel/skill.json +0 -12
  405. package/skills/tfx-persist/SKILL.md.tmpl +0 -269
  406. package/skills/tfx-persist/skill.json +0 -12
  407. package/skills/tfx-plan/skill.json +0 -11
  408. package/skills/tfx-profile/SKILL.md.tmpl +0 -239
  409. package/skills/tfx-profile/skill.json +0 -8
  410. package/skills/tfx-prune/SKILL.md.tmpl +0 -199
  411. package/skills/tfx-prune/skill.json +0 -12
  412. package/skills/tfx-psmux-rules/SKILL.md.tmpl +0 -317
  413. package/skills/tfx-psmux-rules/skill.json +0 -8
  414. package/skills/tfx-qa/skill.json +0 -11
  415. package/skills/tfx-ralph/SKILL.md.tmpl +0 -27
  416. package/skills/tfx-ralph/skill.json +0 -8
  417. package/skills/tfx-remote-setup/SKILL.md.tmpl +0 -576
  418. package/skills/tfx-remote-setup/skill.json +0 -8
  419. package/skills/tfx-remote-spawn/SKILL.md.tmpl +0 -263
  420. package/skills/tfx-remote-spawn/skill.json +0 -9
  421. package/skills/tfx-research/skill.json +0 -13
  422. package/skills/tfx-review/skill.json +0 -11
  423. package/skills/tfx-setup/SKILL.md.tmpl +0 -380
  424. package/skills/tfx-setup/skill.json +0 -8
  425. package/skills/tfx-swarm/SKILL.md.tmpl +0 -154
  426. package/skills/tfx-swarm/skill.json +0 -5
@@ -0,0 +1,280 @@
1
+ // hub/cli-adapter-base.mjs — codex/gemini 공통 CLI adapter 인터페이스
2
+ // Phase 2: codex-adapter.mjs에서 추출한 재사용 가능 유틸리티
3
+
4
+ import { execSync, spawn } from 'node:child_process';
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+
7
+ import { killProcess, IS_WINDOWS } from './platform.mjs';
8
+
9
+ // ── Codex CLI compatibility ─────────────────────────────────────
10
+
11
+ let _cachedVersion = null;
12
+
13
+ /**
14
+ * `codex --version` 실행 결과를 파싱하여 마이너 버전 숫자 반환.
15
+ * 파싱 실패 시 0 반환 (구버전으로 간주).
16
+ * @returns {number} 마이너 버전 (예: 0.117.0 → 117)
17
+ */
18
+ export function getCodexVersion() {
19
+ if (_cachedVersion !== null) return _cachedVersion;
20
+ try {
21
+ const out = execSync('codex --version', { encoding: 'utf8', timeout: 5000 }).trim();
22
+ const match = out.match(/(\d+)\.(\d+)\.(\d+)/);
23
+ _cachedVersion = match ? Number.parseInt(match[2], 10) : 0;
24
+ } catch {
25
+ _cachedVersion = 0;
26
+ }
27
+ return _cachedVersion;
28
+ }
29
+
30
+ /**
31
+ * 최소 마이너 버전 이상인지 확인.
32
+ * @param {number} minMinor
33
+ * @returns {boolean}
34
+ */
35
+ export function gte(minMinor) {
36
+ return getCodexVersion() >= minMinor;
37
+ }
38
+
39
+ /**
40
+ * Codex CLI 기능별 분기 객체.
41
+ * 117 = 0.117.0 (Rust 리라이트, exec 서브커맨드 도입)
42
+ */
43
+ export const FEATURES = {
44
+ /** exec 서브커맨드 사용 가능 여부 */
45
+ get execSubcommand() { return gte(117); },
46
+ /** --output-last-message 플래그 지원 여부 */
47
+ get outputLastMessage() { return gte(117); },
48
+ /** --color never 플래그 지원 여부 */
49
+ get colorNever() { return gte(117); },
50
+ /** 플러그인 시스템 지원 여부 (향후 확장용) */
51
+ get pluginSystem() { return gte(120); },
52
+ };
53
+
54
+ // ── Shell utilities ─────────────────────────────────────────────
55
+
56
+ export function normalizePathForShell(value) {
57
+ return IS_WINDOWS ? String(value).replace(/\\/g, '/') : String(value);
58
+ }
59
+
60
+ export function shellQuote(value) {
61
+ return JSON.stringify(String(value));
62
+ }
63
+
64
+ export function escapePwshSingleQuoted(value) {
65
+ return String(value).replace(/'/g, "''");
66
+ }
67
+
68
+ export const CODEX_MCP_TRANSPORT_EXIT_CODE = 70;
69
+ export const CODEX_MCP_EXECUTION_EXIT_CODE = 1;
70
+
71
+ /**
72
+ * long-form 플래그 기반 명령 빌더.
73
+ * @param {string} prompt
74
+ * @param {string|null} resultFile — null이면 --output-last-message 생략
75
+ * @param {{ profile?: string, skipGitRepoCheck?: boolean, sandboxBypass?: boolean, cwd?: string, mcpServers?: string[] }} [opts]
76
+ * @returns {string} 실행할 셸 커맨드
77
+ */
78
+ export function buildExecCommand(prompt, resultFile = null, opts = {}) {
79
+ const { profile, skipGitRepoCheck = true, sandboxBypass = true, cwd, mcpServers } = opts;
80
+
81
+ const parts = ['codex'];
82
+ if (profile) parts.push('--profile', profile);
83
+
84
+ if (FEATURES.execSubcommand) {
85
+ parts.push('exec');
86
+ if (sandboxBypass) parts.push('--dangerously-bypass-approvals-and-sandbox');
87
+ if (skipGitRepoCheck) parts.push('--skip-git-repo-check');
88
+ if (resultFile && FEATURES.outputLastMessage) {
89
+ parts.push('--output-last-message', resultFile);
90
+ }
91
+ if (FEATURES.colorNever) parts.push('--color', 'never');
92
+ if (cwd) parts.push('--cwd', `'${escapePwshSingleQuoted(cwd)}'`);
93
+ if (Array.isArray(mcpServers)) {
94
+ for (const server of mcpServers) {
95
+ parts.push('-c', `mcp_servers.${server}.enabled=true`);
96
+ }
97
+ }
98
+ } else {
99
+ parts.push('--dangerously-bypass-approvals-and-sandbox');
100
+ if (skipGitRepoCheck) parts.push('--skip-git-repo-check');
101
+ }
102
+
103
+ parts.push(JSON.stringify(prompt));
104
+ return parts.join(' ');
105
+ }
106
+
107
+ // ── Sleep ───────────────────────────────────────────────────────
108
+
109
+ export function sleep(ms) {
110
+ return new Promise((resolve) => {
111
+ const timer = setTimeout(resolve, ms);
112
+ timer.unref?.();
113
+ });
114
+ }
115
+
116
+ // ── Result factory ──────────────────────────────────────────────
117
+
118
+ export function createResult(ok, extra = {}) {
119
+ return {
120
+ ok,
121
+ output: '',
122
+ stderr: '',
123
+ exitCode: null,
124
+ duration: 0,
125
+ retried: false,
126
+ fellBack: false,
127
+ failureMode: ok ? null : 'crash',
128
+ ...extra,
129
+ };
130
+ }
131
+
132
+ export function appendWarnings(stderr, warnings = []) {
133
+ const text = warnings.map((item) => `[preflight] ${item}`).join('\n');
134
+ return [stderr, text].filter(Boolean).join('\n');
135
+ }
136
+
137
+ // ── Circuit breaker factory ─────────────────────────────────────
138
+
139
+ export function createCircuitBreaker(opts = {}) {
140
+ const state = {
141
+ failures: [],
142
+ maxFailures: opts.maxFailures ?? 3,
143
+ windowMs: opts.windowMs ?? 10 * 60_000,
144
+ openedAt: 0,
145
+ trialInFlight: false,
146
+ };
147
+
148
+ function pruneFailures(now = Date.now()) {
149
+ state.failures = state.failures.filter((stamp) => now - stamp < state.windowMs);
150
+ }
151
+
152
+ function reset() {
153
+ state.failures = [];
154
+ state.openedAt = 0;
155
+ state.trialInFlight = false;
156
+ }
157
+
158
+ function recordFailure(isHalfOpen, now = Date.now()) {
159
+ pruneFailures(now);
160
+ state.failures = [...state.failures, now];
161
+ state.trialInFlight = false;
162
+ if (isHalfOpen || state.failures.length >= state.maxFailures) {
163
+ state.openedAt = now;
164
+ }
165
+ }
166
+
167
+ function getState(now = Date.now()) {
168
+ pruneFailures(now);
169
+ const withinWindow = state.openedAt && now - state.openedAt < state.windowMs;
170
+ const current = withinWindow ? 'open' : (state.openedAt ? 'half-open' : 'closed');
171
+ return {
172
+ state: current,
173
+ failures: [...state.failures],
174
+ maxFailures: state.maxFailures,
175
+ windowMs: state.windowMs,
176
+ openedAt: state.openedAt || null,
177
+ trialInFlight: state.trialInFlight,
178
+ };
179
+ }
180
+
181
+ function canExecute() {
182
+ const circuit = getState();
183
+ if (circuit.state === 'open') return { allowed: false, halfOpen: false };
184
+ if (circuit.state === 'half-open' && state.trialInFlight) return { allowed: false, halfOpen: true };
185
+ const halfOpen = circuit.state === 'half-open';
186
+ if (halfOpen) state.trialInFlight = true;
187
+ return { allowed: true, halfOpen };
188
+ }
189
+
190
+ function clearTrial() {
191
+ state.trialInFlight = false;
192
+ }
193
+
194
+ return { getState, recordFailure, reset, canExecute, clearTrial };
195
+ }
196
+
197
+ // ── Process termination ─────────────────────────────────────────
198
+
199
+ export async function terminateChild(pid, opts = {}) {
200
+ if (!pid) return;
201
+ const graceMs = opts.graceMs ?? 5000;
202
+ killProcess(pid, { signal: 'SIGTERM', tree: true, timeout: graceMs });
203
+ await sleep(graceMs);
204
+ killProcess(pid, { signal: 'SIGKILL', tree: true, force: true, timeout: graceMs });
205
+ }
206
+
207
+ // ── Process execution with stall detection ──────────────────────
208
+
209
+ /**
210
+ * Spawn a CLI process with timeout + stall detection.
211
+ *
212
+ * @param {string} command — shell command to run
213
+ * @param {string} workdir — cwd for the child process
214
+ * @param {number} timeout — max duration in ms
215
+ * @param {object} [opts]
216
+ * @param {string} [opts.resultFile] — file to read output from (if CLI writes there)
217
+ * @param {function} [opts.inferStallMode] — (stdout, stderr) => string. Default: () => 'timeout'
218
+ * @param {number} [opts.stallCheckIntervalMs] — stall check interval (default 10_000)
219
+ * @param {number} [opts.stallThresholdMs] — stall threshold (default 30_000)
220
+ * @returns {Promise<object>} createResult-shaped object
221
+ */
222
+ export async function runProcess(command, workdir, timeout, opts = {}) {
223
+ const startedAt = Date.now();
224
+ const inferStallMode = opts.inferStallMode || (() => 'timeout');
225
+ const stallCheckIntervalMs = opts.stallCheckIntervalMs ?? 10_000;
226
+ const stallThresholdMs = opts.stallThresholdMs ?? 30_000;
227
+ const resultFile = opts.resultFile || null;
228
+
229
+ let stdout = '';
230
+ let stderr = '';
231
+ let exitCode = null;
232
+ let failureMode = null;
233
+ let child;
234
+
235
+ try {
236
+ child = spawn(command, { cwd: workdir, shell: true, windowsHide: true });
237
+ } catch (error) {
238
+ return createResult(false, { stderr: String(error?.message || error), duration: Date.now() - startedAt });
239
+ }
240
+
241
+ let lastBytes = 0;
242
+ let lastChange = Date.now();
243
+ const touch = () => { lastChange = Date.now(); };
244
+ child.stdout?.on('data', (chunk) => { stdout += String(chunk); touch(); });
245
+ child.stderr?.on('data', (chunk) => { stderr += String(chunk); touch(); });
246
+ child.on('error', (error) => { stderr += String(error?.message || error); failureMode ||= 'crash'; });
247
+
248
+ const stopFor = async (mode) => {
249
+ if (failureMode) return;
250
+ failureMode = mode;
251
+ await terminateChild(child.pid);
252
+ };
253
+
254
+ const timeoutTimer = setTimeout(() => { void stopFor('timeout'); }, timeout);
255
+ const stallTimer = setInterval(() => {
256
+ const size = Buffer.byteLength(stdout) + Buffer.byteLength(stderr);
257
+ if (size !== lastBytes) {
258
+ lastBytes = size;
259
+ return;
260
+ }
261
+ if (Date.now() - lastChange >= stallThresholdMs) void stopFor(inferStallMode(stdout, stderr));
262
+ }, stallCheckIntervalMs);
263
+ timeoutTimer.unref?.();
264
+ stallTimer.unref?.();
265
+
266
+ await new Promise((resolve) => child.on('close', (code) => { exitCode = code; resolve(); }));
267
+ clearTimeout(timeoutTimer);
268
+ clearInterval(stallTimer);
269
+
270
+ const fileOutput = resultFile && existsSync(resultFile) ? readFileSync(resultFile, 'utf8') : '';
271
+ const output = fileOutput || stdout;
272
+ const ok = failureMode == null && exitCode === 0;
273
+ return createResult(ok, {
274
+ output,
275
+ stderr,
276
+ exitCode,
277
+ duration: Date.now() - startedAt,
278
+ failureMode: ok ? null : (failureMode || 'crash'),
279
+ });
280
+ }
@@ -0,0 +1,199 @@
1
+ import { writeFileSync, mkdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { tmpdir } from 'node:os';
4
+
5
+ import { runPreflight } from './codex-preflight.mjs';
6
+ import { withRetry } from './workers/worker-utils.mjs';
7
+ import {
8
+ createCircuitBreaker,
9
+ createResult,
10
+ appendWarnings,
11
+ buildExecCommand,
12
+ normalizePathForShell,
13
+ shellQuote,
14
+ runProcess,
15
+ } from './cli-adapter-base.mjs';
16
+
17
+ const breaker = createCircuitBreaker();
18
+
19
+ // ── Codex-specific stall inference ──────────────────────────────
20
+
21
+ function inferStallMode(stdout, stderr) {
22
+ const text = `${stdout}\n${stderr}`.toLowerCase();
23
+ if (/(rate.?limit|quota|throttl|too.many.requests|429|usage.limit)/u.test(text)) return 'rate_limited';
24
+ if (/(approval|approve|permission|sandbox|bypass)/u.test(text)) return 'approval_stall';
25
+ if (/\bmcp\b|context7|playwright|tavily|exa|brave|sequential|server/u.test(text)) return 'mcp_stall';
26
+ return 'timeout';
27
+ }
28
+
29
+ // ── Codex command building ──────────────────────────────────────
30
+
31
+ function commandWithOverrides(command, prompt, codexPath, overrides = []) {
32
+ let next = codexPath ? command.replace(/^codex\b/u, shellQuote(codexPath)) : command;
33
+ if (!overrides.length) return next;
34
+ const promptArg = JSON.stringify(prompt);
35
+ const flags = overrides.flatMap((value) => ['-c', shellQuote(value)]).join(' ');
36
+ return next.endsWith(promptArg)
37
+ ? `${next.slice(0, -promptArg.length)}${flags} ${promptArg}`
38
+ : `${next} ${flags}`;
39
+ }
40
+
41
+ function buildOverrides(requested, excluded) {
42
+ return [...new Set((requested || []).filter((name) => (excluded || []).includes(name)))]
43
+ .map((name) => `mcp_servers.${name}.enabled=false`);
44
+ }
45
+
46
+ function buildAttempts(opts, preflight) {
47
+ const timeout = Number.isFinite(opts.timeout) ? opts.timeout : 300_000;
48
+ const requested = Array.isArray(opts.mcpServers) ? [...opts.mcpServers] : [];
49
+ const base = {
50
+ timeout,
51
+ profile: opts.profile,
52
+ requested,
53
+ excluded: [...(preflight.excludeMcpServers || [])],
54
+ forceBypass: preflight.needsBypass,
55
+ };
56
+ if (opts.retryOnFail === false) return [base];
57
+ return [
58
+ base,
59
+ { ...base, timeout: timeout * 2, excluded: requested, forceBypass: true },
60
+ ];
61
+ }
62
+
63
+ // ── Launch script ───────────────────────────────────────────────
64
+
65
+ function createLaunchScriptText(opts) {
66
+ const parts = ['codex'];
67
+ if (opts.profile) parts.push('--profile', shellQuote(opts.profile));
68
+ parts.push(
69
+ 'exec',
70
+ '--dangerously-bypass-approvals-and-sandbox',
71
+ '--skip-git-repo-check',
72
+ '$(cat "$PROMPT_FILE")',
73
+ );
74
+ return [
75
+ '#!/usr/bin/env bash',
76
+ 'set -euo pipefail',
77
+ `cd ${shellQuote(normalizePathForShell(opts.workdir))}`,
78
+ `PROMPT_FILE=${shellQuote(normalizePathForShell(opts.promptFile))}`,
79
+ `TFX_CODEX_TIMEOUT_MS=${shellQuote(String(opts.timeout ?? ''))}`,
80
+ parts.join(' '),
81
+ '',
82
+ ].join('\n');
83
+ }
84
+
85
+ export function buildLaunchScript(opts = {}) {
86
+ const dir = join(tmpdir(), 'triflux-codex-launch');
87
+ mkdirSync(dir, { recursive: true });
88
+ const path = join(dir, `${String(opts.id || 'launch')}.sh`);
89
+ writeFileSync(path, createLaunchScriptText(opts), 'utf8');
90
+ return path;
91
+ }
92
+
93
+ // ── Exec args builder ───────────────────────────────────────────
94
+
95
+ export function buildExecArgs(opts = {}) {
96
+ const prompt = typeof opts.prompt === 'string' ? opts.prompt : '';
97
+ const command = buildExecCommand(prompt, opts.resultFile || null, {
98
+ profile: opts.profile,
99
+ skipGitRepoCheck: true,
100
+ sandboxBypass: true,
101
+ cwd: opts.cwd,
102
+ });
103
+
104
+ if (!prompt) return command.replace(/\s+""$/u, '');
105
+
106
+ let result;
107
+ const quotedPrompt = JSON.stringify(prompt);
108
+ if (/^\(Get-Content\b[\s\S]*\)$/u.test(prompt) && command.endsWith(quotedPrompt)) {
109
+ result = `${command.slice(0, -quotedPrompt.length)}${prompt}`;
110
+ } else {
111
+ result = command;
112
+ }
113
+
114
+ // stderr 캡처: codex 실패 시에도 원인 추적 가능 (resultFile.err)
115
+ if (opts.resultFile) {
116
+ result += ` 2>'${opts.resultFile}.err'`;
117
+ }
118
+ return result;
119
+ }
120
+
121
+ // ── Codex execution ─────────────────────────────────────────────
122
+
123
+ async function runCodex(prompt, workdir, preflight, attempt) {
124
+ const dir = join(tmpdir(), 'triflux-codex-exec');
125
+ mkdirSync(dir, { recursive: true });
126
+ const resultFile = join(dir, `codex-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`);
127
+ const command = commandWithOverrides(
128
+ buildExecCommand(prompt, resultFile, {
129
+ profile: attempt.profile,
130
+ skipGitRepoCheck: true,
131
+ sandboxBypass: attempt.forceBypass,
132
+ }),
133
+ prompt,
134
+ preflight.codexPath,
135
+ buildOverrides(attempt.requested, attempt.excluded),
136
+ );
137
+ return runProcess(command, workdir, attempt.timeout, { resultFile, inferStallMode });
138
+ }
139
+
140
+ // ── Public API ──────────────────────────────────────────────────
141
+
142
+ export function getCircuitState(now) {
143
+ return breaker.getState(now);
144
+ }
145
+
146
+ export async function execute(opts = {}) {
147
+ const entry = breaker.canExecute();
148
+ if (!entry.allowed) {
149
+ return createResult(false, { fellBack: true, failureMode: 'circuit_open' });
150
+ }
151
+
152
+ const preflight = await runPreflight({ mcpServers: opts.mcpServers, subcommand: 'exec' });
153
+ if (!preflight.ok) {
154
+ breaker.clearTrial();
155
+ breaker.recordFailure(entry.halfOpen);
156
+ return createResult(false, {
157
+ stderr: appendWarnings('', preflight.warnings),
158
+ fellBack: opts.fallbackToClaude !== false,
159
+ failureMode: 'crash',
160
+ });
161
+ }
162
+
163
+ const attempts = buildAttempts(opts, preflight);
164
+ let attemptIndex = 0;
165
+ let lastResult = createResult(false);
166
+
167
+ try {
168
+ lastResult = await withRetry(async () => {
169
+ const result = await runCodex(opts.prompt || '', opts.workdir || process.cwd(), preflight, attempts[attemptIndex]);
170
+ const current = { ...result, stderr: appendWarnings(result.stderr, preflight.warnings), retried: attemptIndex > 0 };
171
+ const canRetry = !current.ok && attemptIndex < attempts.length - 1;
172
+ attemptIndex += 1;
173
+ if (!canRetry) return current;
174
+ const error = new Error('retry');
175
+ error.retryable = true;
176
+ error.result = current;
177
+ throw error;
178
+ }, {
179
+ maxAttempts: attempts.length,
180
+ baseDelayMs: 250,
181
+ maxDelayMs: 750,
182
+ shouldRetry: (error) => error?.retryable === true,
183
+ });
184
+ } catch (error) {
185
+ lastResult = error?.result || createResult(false, { stderr: String(error?.message || error) });
186
+ }
187
+
188
+ if (lastResult.ok) {
189
+ breaker.reset();
190
+ return lastResult;
191
+ }
192
+
193
+ breaker.recordFailure(entry.halfOpen);
194
+ return {
195
+ ...lastResult,
196
+ retried: attempts.length > 1,
197
+ fellBack: opts.fallbackToClaude !== false,
198
+ };
199
+ }
@@ -0,0 +1,11 @@
1
+ // hub/codex-compat.mjs — backward-compatible facade for legacy imports
2
+
3
+ export {
4
+ CODEX_MCP_EXECUTION_EXIT_CODE,
5
+ CODEX_MCP_TRANSPORT_EXIT_CODE,
6
+ FEATURES,
7
+ buildExecCommand,
8
+ escapePwshSingleQuoted,
9
+ getCodexVersion,
10
+ gte,
11
+ } from './cli-adapter-base.mjs';
@@ -0,0 +1,166 @@
1
+ import { readFileSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { execSync } from 'node:child_process';
5
+
6
+ import { whichCommandAsync } from './platform.mjs';
7
+
8
+ const MIN_RECOMMENDED_MINOR = 118;
9
+ let _cachedVersion = null;
10
+
11
+ function escapeRegExp(value) {
12
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
13
+ }
14
+
15
+ function readConfigText(configPath = join(homedir(), '.codex', 'config.toml')) {
16
+ if (!existsSync(configPath)) return '';
17
+ try {
18
+ return readFileSync(configPath, 'utf8');
19
+ } catch {
20
+ return '';
21
+ }
22
+ }
23
+
24
+ function readTomlString(text, key) {
25
+ const match = String(text).match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, 'mu'));
26
+ return match?.[1] ?? null;
27
+ }
28
+
29
+ function readSection(text, name) {
30
+ const lines = String(text).split(/\r?\n/u);
31
+ const header = `[${name}]`;
32
+ const start = lines.findIndex((line) => line.trim() === header);
33
+ if (start < 0) return '';
34
+ const body = [];
35
+ for (const line of lines.slice(start + 1)) {
36
+ if (/^\s*\[[^\]]+\]\s*$/u.test(line)) break;
37
+ body.push(line);
38
+ }
39
+ return body.join('\n');
40
+ }
41
+
42
+ /**
43
+ * `codex --version` 실행 결과를 파싱하여 마이너 버전 숫자 반환.
44
+ * 파싱 실패 시 0 반환 (구버전으로 간주).
45
+ * @returns {number} 마이너 버전 (예: 0.117.0 → 117)
46
+ */
47
+ export function getCodexVersion() {
48
+ if (_cachedVersion !== null) return _cachedVersion;
49
+ try {
50
+ const out = execSync('codex --version', { encoding: 'utf8', timeout: 5000 }).trim();
51
+ // "codex 0.117.0" 또는 "0.117.0" 형식 대응
52
+ const match = out.match(/(\d+)\.(\d+)\.(\d+)/);
53
+ _cachedVersion = match ? parseInt(match[2], 10) : 0;
54
+ } catch {
55
+ _cachedVersion = 0;
56
+ }
57
+ return _cachedVersion;
58
+ }
59
+
60
+ async function checkCodexInstalled() {
61
+ const codexPath = await whichCommandAsync('codex');
62
+ if (codexPath) return { codexPath, ok: true, warnings: [] };
63
+ return {
64
+ codexPath: null,
65
+ ok: false,
66
+ warnings: ['Codex CLI not found. Install Codex and ensure `codex` is available on PATH.'],
67
+ };
68
+ }
69
+
70
+ function checkCodexVersion() {
71
+ const version = getCodexVersion();
72
+ const warnings = version >= MIN_RECOMMENDED_MINOR
73
+ ? []
74
+ : [`Codex CLI 0.${version}.x detected; 0.${MIN_RECOMMENDED_MINOR}.x or newer is recommended.`];
75
+ return { version, warnings };
76
+ }
77
+
78
+ function checkApprovalMode(configText, opts = {}) {
79
+ const approvalMode = readTomlString(configText, 'approval_mode');
80
+ const sandbox = readTomlString(configText, 'sandbox');
81
+ const subcommand = opts.subcommand || 'exec';
82
+ return {
83
+ needsBypass: subcommand === 'exec' || approvalMode !== 'full-auto',
84
+ approvalMode,
85
+ sandbox,
86
+ };
87
+ }
88
+
89
+ async function verifyServerHealth(name, configText) {
90
+ const section = readSection(configText, `mcp_servers.${name}`);
91
+ if (!section) return { ok: false, warning: `MCP server '${name}' is not configured.` };
92
+ if (/^\s*enabled\s*=\s*false\s*$/mu.test(section)) {
93
+ return { ok: false, warning: `MCP server '${name}' is disabled in config.toml.` };
94
+ }
95
+
96
+ const command = readTomlString(section, 'command');
97
+ if (command) {
98
+ const resolved = await whichCommandAsync(command);
99
+ return resolved
100
+ ? { ok: true, warning: '' }
101
+ : { ok: false, warning: `MCP server '${name}' command not found: ${command}` };
102
+ }
103
+
104
+ const url = readTomlString(section, 'url');
105
+ if (!url || !/^https?:\/\//u.test(url)) return { ok: true, warning: '' };
106
+ try {
107
+ const response = await fetch(url, { signal: AbortSignal.timeout(2000) });
108
+ return response.status < 500
109
+ ? { ok: true, warning: '' }
110
+ : { ok: false, warning: `MCP server '${name}' returned HTTP ${response.status}.` };
111
+ } catch {
112
+ return { ok: false, warning: `MCP server '${name}' is unreachable at ${url}.` };
113
+ }
114
+ }
115
+
116
+ async function checkMcpHealth(mcpServers, configText) {
117
+ const excludeMcpServers = [];
118
+ const warnings = [];
119
+
120
+ for (const name of Array.isArray(mcpServers) ? mcpServers : []) {
121
+ const server = String(name ?? '').trim();
122
+ if (!server) continue;
123
+ const result = await verifyServerHealth(server, configText);
124
+ if (!result.ok) excludeMcpServers.push(server);
125
+ if (result.warning) warnings.push(result.warning);
126
+ }
127
+
128
+ return { excludeMcpServers, warnings };
129
+ }
130
+
131
+ export async function runPreflight(opts = {}) {
132
+ const install = await checkCodexInstalled();
133
+ if (!install.ok) {
134
+ return {
135
+ codexPath: null,
136
+ version: 0,
137
+ needsBypass: true,
138
+ excludeMcpServers: [],
139
+ warnings: install.warnings,
140
+ ok: false,
141
+ };
142
+ }
143
+
144
+ const warnings = [...install.warnings];
145
+ const { version, warnings: versionWarnings } = checkCodexVersion();
146
+ warnings.push(...versionWarnings);
147
+
148
+ const configText = readConfigText(opts.configPath);
149
+ const approval = checkApprovalMode(configText, opts);
150
+ if (approval.approvalMode !== 'full-auto') {
151
+ warnings.push(`approval_mode is '${approval.approvalMode || 'unset'}'; bypass flag will be used.`);
152
+ }
153
+ if (approval.sandbox) warnings.push(`sandbox mode from config.toml: ${approval.sandbox}`);
154
+
155
+ const mcp = await checkMcpHealth(opts.mcpServers, configText);
156
+ warnings.push(...mcp.warnings);
157
+
158
+ return {
159
+ codexPath: install.codexPath,
160
+ version,
161
+ needsBypass: approval.needsBypass,
162
+ excludeMcpServers: mcp.excludeMcpServers,
163
+ warnings,
164
+ ok: true,
165
+ };
166
+ }
@@ -0,0 +1,37 @@
1
+ export const DELEGATOR_MCP_SERVER_INFO = Object.freeze({
2
+ name: 'triflux-delegator',
3
+ version: '0.1.0',
4
+ });
5
+
6
+ export const DELEGATOR_TOOL_NAMES = Object.freeze({
7
+ delegate: 'delegate',
8
+ delegateReply: 'delegate-reply',
9
+ status: 'status',
10
+ });
11
+
12
+ export const DELEGATOR_PIPE_ACTIONS = Object.freeze({
13
+ delegate: 'delegator_delegate',
14
+ delegateReply: 'delegator_reply',
15
+ status: 'delegator_status',
16
+ });
17
+
18
+ export const DELEGATOR_JOB_STATUSES = Object.freeze([
19
+ 'queued',
20
+ 'running',
21
+ 'waiting_reply',
22
+ 'completed',
23
+ 'failed',
24
+ ]);
25
+
26
+ export const DELEGATOR_MODES = Object.freeze([
27
+ 'sync',
28
+ 'async',
29
+ ]);
30
+
31
+ export const DELEGATOR_PROVIDERS = Object.freeze([
32
+ 'auto',
33
+ 'codex',
34
+ 'gemini',
35
+ ]);
36
+
37
+ export const DELEGATOR_SCHEMA_URL = new URL('./schema/delegator-tools.schema.json', import.meta.url);