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,21 @@
1
+ // hub/workers/factory.mjs — Worker 생성 팩토리
2
+
3
+ import { GeminiWorker } from './gemini-worker.mjs';
4
+ import { ClaudeWorker } from './claude-worker.mjs';
5
+ import { CodexMcpWorker } from './codex-mcp.mjs';
6
+ import { DelegatorMcpWorker } from './delegator-mcp.mjs';
7
+
8
+ export function createWorker(type, opts = {}) {
9
+ switch (type) {
10
+ case 'gemini':
11
+ return new GeminiWorker(opts);
12
+ case 'claude':
13
+ return new ClaudeWorker(opts);
14
+ case 'codex':
15
+ return new CodexMcpWorker(opts);
16
+ case 'delegator':
17
+ return new DelegatorMcpWorker(opts);
18
+ default:
19
+ throw new Error(`Unknown worker type: ${type}`);
20
+ }
21
+ }
@@ -0,0 +1,374 @@
1
+ // hub/workers/gemini-worker.mjs — Gemini headless subprocess 래퍼
2
+ // ADR-006: --output-format stream-json 기반 단발 실행 워커.
3
+
4
+ import { spawn } from 'node:child_process';
5
+ import { isAbsolute } from 'node:path';
6
+ import readline from 'node:readline';
7
+
8
+ import { extractText, terminateChild, withRetry } from './worker-utils.mjs';
9
+
10
+ const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
11
+ const DEFAULT_KILL_GRACE_MS = 1000;
12
+
13
+ function toStringList(value) {
14
+ if (!Array.isArray(value)) return [];
15
+ return value
16
+ .map((item) => String(item ?? '').trim())
17
+ .filter(Boolean);
18
+ }
19
+
20
+ function safeJsonParse(line) {
21
+ try {
22
+ return JSON.parse(line);
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+
28
+ function findLastEvent(events, predicate) {
29
+ for (let index = events.length - 1; index >= 0; index -= 1) {
30
+ if (predicate(events[index])) return events[index];
31
+ }
32
+ return null;
33
+ }
34
+
35
+ function buildGeminiArgs(options) {
36
+ const args = [];
37
+
38
+ if (options.model) {
39
+ args.push('--model', options.model);
40
+ }
41
+
42
+ if (options.approvalMode) {
43
+ args.push('--approval-mode', options.approvalMode);
44
+ } else if (options.yolo !== false) {
45
+ args.push('--yolo');
46
+ }
47
+
48
+ const allowedMcpServers = toStringList(options.allowedMcpServerNames);
49
+ if (allowedMcpServers.length) {
50
+ args.push('--allowed-mcp-server-names', ...allowedMcpServers);
51
+ }
52
+
53
+ const extraArgs = toStringList(options.extraArgs);
54
+ if (extraArgs.length) args.push(...extraArgs);
55
+
56
+ args.push('--prompt', options.promptArgument ?? '');
57
+ args.push('--output-format', 'stream-json');
58
+
59
+ return args;
60
+ }
61
+
62
+ function createWorkerError(message, details = {}) {
63
+ const error = new Error(message);
64
+ Object.assign(error, details);
65
+ return error;
66
+ }
67
+
68
+ function normalizeRetryOptions(retryOptions) {
69
+ if (!retryOptions || typeof retryOptions !== 'object') {
70
+ return Object.freeze({});
71
+ }
72
+ return Object.freeze({ ...retryOptions });
73
+ }
74
+
75
+ function isGeminiRetryable(error) {
76
+ return error?.code === 'WORKER_EXIT'
77
+ && error?.result?.exitCode !== 0
78
+ && error?.result?.exitCode !== 2;
79
+ }
80
+
81
+ function detectGeminiCategory(error) {
82
+ const combined = `${error?.message || ''}\n${error?.stderr || ''}`.toLowerCase();
83
+
84
+ if (/(unauthorized|forbidden|auth|login|token|credential|apikey|api key)/.test(combined)) {
85
+ return 'auth';
86
+ }
87
+ if (error?.result?.exitCode === 2 || /expected stream-json|unknown option|invalid option|config/.test(combined)) {
88
+ return 'config';
89
+ }
90
+ if (error?.code === 'WORKER_EVENT_ERROR') {
91
+ return 'input';
92
+ }
93
+
94
+ return 'transient';
95
+ }
96
+
97
+ function buildGeminiErrorInfo(error, attempts) {
98
+ const category = detectGeminiCategory(error);
99
+ const retryable = isGeminiRetryable(error);
100
+ let recovery = 'Retry the Gemini worker after correcting the reported issue.';
101
+
102
+ if (category === 'auth') {
103
+ recovery = 'Refresh the Gemini authentication state and retry.';
104
+ } else if (category === 'config') {
105
+ recovery = 'Check the Gemini CLI flags and worker configuration.';
106
+ } else if (category === 'input') {
107
+ recovery = 'Check the Gemini request payload and streamed event format.';
108
+ }
109
+
110
+ return Object.freeze({
111
+ code: error?.code || 'GEMINI_EXECUTION_ERROR',
112
+ retryable,
113
+ attempts,
114
+ category,
115
+ recovery,
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Gemini stream-json 래퍼
121
+ */
122
+ export class GeminiWorker {
123
+ type = 'gemini';
124
+
125
+ constructor(options = {}) {
126
+ this.command = options.command || 'gemini';
127
+ this.commandArgs = toStringList(options.commandArgs || options.args);
128
+ this.cwd = options.cwd || process.cwd();
129
+ this.env = { ...process.env, ...(options.env || {}) };
130
+ this.model = options.model || null;
131
+ this.approvalMode = options.approvalMode || null;
132
+ this.yolo = options.yolo !== false;
133
+ this.allowedMcpServerNames = toStringList(options.allowedMcpServerNames);
134
+ this.extraArgs = toStringList(options.extraArgs);
135
+ this.timeoutMs = Number(options.timeoutMs) > 0 ? Number(options.timeoutMs) : DEFAULT_TIMEOUT_MS;
136
+ this.killGraceMs = Number(options.killGraceMs) > 0 ? Number(options.killGraceMs) : DEFAULT_KILL_GRACE_MS;
137
+ this.retryOptions = normalizeRetryOptions(options.retryOptions);
138
+ this.onEvent = typeof options.onEvent === 'function' ? options.onEvent : null;
139
+
140
+ this.state = 'idle';
141
+ this.child = null;
142
+ this.lastRun = null;
143
+ }
144
+
145
+ getStatus() {
146
+ return {
147
+ type: 'gemini',
148
+ state: this.state,
149
+ pid: this.child?.pid || null,
150
+ last_run_at_ms: this.lastRun?.finishedAtMs || null,
151
+ last_exit_code: this.lastRun?.exitCode ?? null,
152
+ };
153
+ }
154
+
155
+ async start() {
156
+ if (this.state === 'stopped') {
157
+ this.state = 'idle';
158
+ }
159
+ return this.getStatus();
160
+ }
161
+
162
+ async stop() {
163
+ if (!this.child) {
164
+ this.state = 'stopped';
165
+ return this.getStatus();
166
+ }
167
+ const child = this.child;
168
+ terminateChild(child, this.killGraceMs);
169
+ await new Promise((resolve) => {
170
+ child.once('close', resolve);
171
+ setTimeout(resolve, this.killGraceMs + 50).unref?.();
172
+ });
173
+ this.child = null;
174
+ this.state = 'stopped';
175
+ return this.getStatus();
176
+ }
177
+
178
+ async restart() {
179
+ await this.stop();
180
+ this.state = 'idle';
181
+ return this.getStatus();
182
+ }
183
+
184
+ async run(prompt, options = {}) {
185
+ if (this.child) {
186
+ throw createWorkerError('GeminiWorker is already running', { code: 'WORKER_BUSY' });
187
+ }
188
+
189
+ await this.start();
190
+
191
+ const timeoutMs = Number(options.timeoutMs) > 0 ? Number(options.timeoutMs) : this.timeoutMs;
192
+ const startedAtMs = Date.now();
193
+ const args = [
194
+ ...this.commandArgs,
195
+ ...buildGeminiArgs({
196
+ model: options.model || this.model,
197
+ approvalMode: options.approvalMode || this.approvalMode,
198
+ yolo: options.yolo ?? this.yolo,
199
+ allowedMcpServerNames: options.allowedMcpServerNames || this.allowedMcpServerNames,
200
+ extraArgs: options.extraArgs || this.extraArgs,
201
+ promptArgument: options.promptArgument ?? '',
202
+ }),
203
+ ];
204
+
205
+ const child = spawn(this.command, args, {
206
+ cwd: options.cwd || this.cwd,
207
+ env: { ...this.env, ...(options.env || {}) },
208
+ stdio: ['pipe', 'pipe', 'pipe'],
209
+ windowsHide: true,
210
+ shell: process.platform === 'win32' && !isAbsolute(this.command),
211
+ });
212
+
213
+ this.child = child;
214
+ this.state = 'running';
215
+
216
+ const events = [];
217
+ const stdoutLines = [];
218
+ const stderrLines = [];
219
+ let lastErrorEvent = null;
220
+ let timedOut = false;
221
+ let exitCode = null;
222
+ let exitSignal = null;
223
+
224
+ const stdoutReader = readline.createInterface({
225
+ input: child.stdout,
226
+ crlfDelay: Infinity,
227
+ });
228
+ const stderrReader = readline.createInterface({
229
+ input: child.stderr,
230
+ crlfDelay: Infinity,
231
+ });
232
+
233
+ stdoutReader.on('line', (line) => {
234
+ if (!line) return;
235
+ const event = safeJsonParse(line);
236
+ if (!event) {
237
+ stdoutLines.push(line);
238
+ return;
239
+ }
240
+
241
+ events.push(event);
242
+ if (event.type === 'error') lastErrorEvent = event;
243
+ if (this.onEvent) {
244
+ try { this.onEvent(event); } catch {}
245
+ }
246
+ });
247
+
248
+ stderrReader.on('line', (line) => {
249
+ if (!line) return;
250
+ stderrLines.push(line);
251
+ });
252
+
253
+ const closePromise = new Promise((resolve, reject) => {
254
+ child.once('error', reject);
255
+ child.once('close', (code, signal) => {
256
+ exitCode = code;
257
+ exitSignal = signal;
258
+ resolve();
259
+ });
260
+ });
261
+
262
+ const timeout = setTimeout(() => {
263
+ timedOut = true;
264
+ terminateChild(child, this.killGraceMs);
265
+ }, timeoutMs);
266
+ timeout.unref?.();
267
+
268
+ child.stdin.on('error', () => {});
269
+ child.stdin.end(String(prompt ?? ''));
270
+
271
+ try {
272
+ await closePromise;
273
+ } finally {
274
+ clearTimeout(timeout);
275
+ stdoutReader.close();
276
+ stderrReader.close();
277
+ if (this.child === child) {
278
+ this.child = null;
279
+ }
280
+ this.state = 'idle';
281
+ }
282
+
283
+ const resultEvent = findLastEvent(events, (event) => event?.type === 'result');
284
+ const response = [
285
+ extractText(resultEvent),
286
+ ...events
287
+ .filter((event) => event?.type === 'message' || event?.type === 'assistant')
288
+ .map((event) => extractText(event))
289
+ .filter(Boolean),
290
+ ...stdoutLines,
291
+ ]
292
+ .filter(Boolean)
293
+ .join('\n')
294
+ .trim();
295
+
296
+ const result = {
297
+ type: 'gemini',
298
+ command: this.command,
299
+ args,
300
+ response,
301
+ events,
302
+ resultEvent,
303
+ usage: resultEvent?.usage || null,
304
+ stdout: stdoutLines.join('\n').trim(),
305
+ stderr: stderrLines.join('\n').trim(),
306
+ exitCode,
307
+ exitSignal,
308
+ timedOut,
309
+ startedAtMs,
310
+ finishedAtMs: Date.now(),
311
+ };
312
+
313
+ this.lastRun = result;
314
+
315
+ if (timedOut) {
316
+ throw createWorkerError(`Gemini worker timed out after ${timeoutMs}ms`, {
317
+ code: 'ETIMEDOUT',
318
+ result,
319
+ stderr: result.stderr,
320
+ });
321
+ }
322
+
323
+ if (exitCode !== 0) {
324
+ throw createWorkerError(`Gemini worker exited with code ${exitCode}`, {
325
+ code: 'WORKER_EXIT',
326
+ result,
327
+ stderr: result.stderr,
328
+ });
329
+ }
330
+
331
+ if (lastErrorEvent) {
332
+ throw createWorkerError('Gemini worker emitted an error event', {
333
+ code: 'WORKER_EVENT_ERROR',
334
+ result,
335
+ stderr: result.stderr,
336
+ });
337
+ }
338
+
339
+ return result;
340
+ }
341
+
342
+ isReady() {
343
+ return this.state !== 'stopped';
344
+ }
345
+
346
+ async execute(prompt, options = {}) {
347
+ let attempts = 0;
348
+
349
+ try {
350
+ const result = await withRetry(async () => {
351
+ attempts += 1;
352
+ return this.run(prompt, options);
353
+ }, {
354
+ ...this.retryOptions,
355
+ shouldRetry: (error) => isGeminiRetryable(error),
356
+ });
357
+
358
+ return {
359
+ output: result.response,
360
+ exitCode: 0,
361
+ sessionKey: options.sessionKey || null,
362
+ raw: result,
363
+ };
364
+ } catch (error) {
365
+ return {
366
+ output: error.stderr || error.message || 'Gemini worker failed',
367
+ exitCode: error.code === 'ETIMEDOUT' ? 124 : 1,
368
+ sessionKey: options.sessionKey || null,
369
+ error: buildGeminiErrorInfo(error, attempts || 1),
370
+ raw: error.result || null,
371
+ };
372
+ }
373
+ }
374
+ }
@@ -0,0 +1,52 @@
1
+ // hub/workers/interface.mjs — Worker 공통 인터페이스 정의
2
+
3
+ /**
4
+ * 워커 실행 옵션
5
+ * @typedef {object} WorkerExecuteOptions
6
+ * @property {string} [cwd] - 워커 작업 디렉터리
7
+ * @property {string} [sessionKey] - 내부 세션 키
8
+ * @property {string} [threadId] - 외부에서 지정한 Codex threadId
9
+ * @property {boolean} [resetSession] - 기존 세션을 무시하고 새 세션 시작 여부
10
+ * @property {string} [model] - Codex 모델 이름
11
+ * @property {string} [profile] - Codex 프로필 이름
12
+ * @property {'untrusted'|'on-failure'|'on-request'|'never'} [approvalPolicy] - 승인 정책
13
+ * @property {'read-only'|'workspace-write'|'danger-full-access'} [sandbox] - 샌드박스 정책
14
+ * @property {Record<string, unknown>} [config] - 추가 Codex 설정
15
+ * @property {string} [baseInstructions] - 기본 시스템 지침
16
+ * @property {string} [developerInstructions] - 개발자 지침
17
+ * @property {string} [compactPrompt] - 컴팩션 프롬프트
18
+ * @property {number} [timeoutMs] - MCP 요청 타임아웃(ms)
19
+ */
20
+
21
+ /**
22
+ * 워커 구조화 오류 메타데이터
23
+ * @typedef {object} WorkerErrorInfo
24
+ * @property {string} code - 오류 코드
25
+ * @property {boolean} retryable - 재시도 대상 여부
26
+ * @property {number} attempts - 실행 시도 횟수
27
+ * @property {'transient'|'auth'|'config'|'input'} category - 오류 분류
28
+ * @property {string} recovery - 권장 복구 가이드
29
+ */
30
+
31
+ /**
32
+ * 워커 실행 결과
33
+ * @typedef {object} WorkerResult
34
+ * @property {string} output - 최종 텍스트 출력
35
+ * @property {number} exitCode - 종료 코드(0=성공)
36
+ * @property {string | null} [threadId] - Codex 세션 threadId
37
+ * @property {string | null} [sessionKey] - 내부 세션 키
38
+ * @property {WorkerErrorInfo} [error] - 구조화 오류 메타데이터
39
+ * @property {unknown} [raw] - 원본 tool call 결과
40
+ */
41
+
42
+ /**
43
+ * 공통 워커 인터페이스
44
+ * @typedef {object} IWorker
45
+ * @property {(prompt: string, opts?: WorkerExecuteOptions) => Promise<WorkerResult>} execute
46
+ * @property {() => Promise<void>} start
47
+ * @property {() => Promise<void>} stop
48
+ * @property {() => boolean} isReady
49
+ * @property {string} type - 'codex' | 'gemini' | 'claude' | 'delegator'
50
+ */
51
+
52
+ export const WORKER_TYPES = Object.freeze(['codex', 'gemini', 'claude', 'delegator']);
@@ -0,0 +1,104 @@
1
+ // hub/workers/worker-utils.mjs — 워커 공통 유틸리티
2
+ // claude-worker, gemini-worker, pipe 등에서 공유하는 순수 유틸 함수 모음.
3
+
4
+ export const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
5
+ export const DEFAULT_KILL_GRACE_MS = 1000;
6
+
7
+ export function toStringList(value) {
8
+ if (!Array.isArray(value)) return [];
9
+ return value
10
+ .map((item) => String(item ?? '').trim())
11
+ .filter(Boolean);
12
+ }
13
+
14
+ export function safeJsonParse(line) {
15
+ try {
16
+ return JSON.parse(line);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ export function createWorkerError(message, details = {}) {
23
+ const error = new Error(message);
24
+ Object.assign(error, details);
25
+ return error;
26
+ }
27
+
28
+ function sleep(delayMs) {
29
+ return new Promise((resolve) => {
30
+ const timer = setTimeout(resolve, Math.max(0, delayMs));
31
+ timer.unref?.();
32
+ });
33
+ }
34
+
35
+ export async function withRetry(fn, opts = {}) {
36
+ const {
37
+ maxAttempts = 3,
38
+ baseDelayMs = 1000,
39
+ maxDelayMs = 15000,
40
+ shouldRetry = () => true,
41
+ } = opts;
42
+
43
+ let lastError;
44
+
45
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
46
+ try {
47
+ return await fn();
48
+ } catch (error) {
49
+ lastError = error;
50
+ if (attempt >= maxAttempts || !shouldRetry(error, attempt)) {
51
+ throw error;
52
+ }
53
+
54
+ const delay = Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs)
55
+ * (0.5 + Math.random() * 0.5);
56
+ await sleep(delay);
57
+ }
58
+ }
59
+
60
+ throw lastError;
61
+ }
62
+
63
+ export function appendTextFragments(value, parts) {
64
+ if (value == null) return;
65
+
66
+ if (typeof value === 'string') {
67
+ const trimmed = value.trim();
68
+ if (trimmed) parts.push(trimmed);
69
+ return;
70
+ }
71
+
72
+ if (Array.isArray(value)) {
73
+ for (const item of value) appendTextFragments(item, parts);
74
+ return;
75
+ }
76
+
77
+ if (typeof value !== 'object') return;
78
+
79
+ if (typeof value.text === 'string') appendTextFragments(value.text, parts);
80
+ if (typeof value.response === 'string') appendTextFragments(value.response, parts);
81
+ if (typeof value.result === 'string') appendTextFragments(value.result, parts);
82
+ if (value.content != null) appendTextFragments(value.content, parts);
83
+ if (value.message != null) appendTextFragments(value.message, parts);
84
+ }
85
+
86
+ export function extractText(value) {
87
+ const parts = [];
88
+ appendTextFragments(value, parts);
89
+ return parts.join('\n').trim();
90
+ }
91
+
92
+ export function terminateChild(child, killGraceMs) {
93
+ if (!child || child.exitCode !== null || child.killed) return;
94
+
95
+ try { child.stdin.end(); } catch {}
96
+ try { child.kill(); } catch {}
97
+
98
+ const timer = setTimeout(() => {
99
+ if (child.exitCode === null) {
100
+ try { child.kill('SIGKILL'); } catch {}
101
+ }
102
+ }, killGraceMs);
103
+ timer.unref?.();
104
+ }
package/hud/colors.mjs ADDED
@@ -0,0 +1,88 @@
1
+ // ============================================================================
2
+ // ANSI 색상 (OMC colors.js 스키마 일치)
3
+ // ============================================================================
4
+ export const RESET = "\x1b[0m";
5
+ export const DIM = "\x1b[2m";
6
+ export const BOLD = "\x1b[1m";
7
+ export const RED = "\x1b[31m";
8
+ export const GREEN = "\x1b[32m";
9
+ export const YELLOW = "\x1b[33m";
10
+ export const CYAN = "\x1b[36m";
11
+ export const CLAUDE_ORANGE = "\x1b[38;2;232;112;64m"; // #E87040 (Claude 공식 오렌지)
12
+ export const CODEX_WHITE = "\x1b[97m"; // bright white (SGR 37은 Windows Terminal에서 연회색 매핑)
13
+ export const GEMINI_BLUE = "\x1b[38;5;39m";
14
+
15
+ export function green(t) { return `${GREEN}${t}${RESET}`; }
16
+ export function yellow(t) { return `${YELLOW}${t}${RESET}`; }
17
+ export function red(t) { return `${RED}${t}${RESET}`; }
18
+ export function cyan(t) { return `${CYAN}${t}${RESET}`; }
19
+ export function dim(t) { return `${DIM}${t}${RESET}`; }
20
+ export function bold(t) { return `${BOLD}${t}${RESET}`; }
21
+ export function claudeOrange(t) { return `${CLAUDE_ORANGE}${t}${RESET}`; }
22
+ export function codexWhite(t) { return `${CODEX_WHITE}${t}${RESET}`; }
23
+ export function geminiBlue(t) { return `${GEMINI_BLUE}${t}${RESET}`; }
24
+
25
+ export function colorByPercent(value, text) {
26
+ if (value >= 85) return red(text);
27
+ if (value >= 70) return yellow(text);
28
+ if (value >= 50) return cyan(text);
29
+ return green(text);
30
+ }
31
+
32
+ export function colorCooldown(seconds, text) {
33
+ if (seconds > 120) return red(text);
34
+ if (seconds > 0) return yellow(text);
35
+ return dim(text);
36
+ }
37
+
38
+ export function colorParallel(current, cap) {
39
+ if (current >= cap) return green(`${current}/${cap}`);
40
+ if (current > 1) return yellow(`${current}/${cap}`);
41
+ return red(`${current}/${cap}`);
42
+ }
43
+
44
+ export const GAUGE_WIDTH = 5;
45
+ export const GAUGE_BLOCKS = ["░", "▒", "▓", "█"]; // 밝기 0~3
46
+
47
+ export function coloredBar(percent, width = GAUGE_WIDTH, baseColor = null) {
48
+ const safePercent = Math.min(100, Math.max(0, percent));
49
+ const perBlock = 100 / width;
50
+
51
+ // 상태별 색상
52
+ let barColor;
53
+ if (safePercent >= 85) barColor = RED;
54
+ else if (safePercent >= 70) barColor = YELLOW;
55
+ else barColor = baseColor || GREEN;
56
+
57
+ let bar = "";
58
+ for (let i = 0; i < width; i++) {
59
+ const blockStart = i * perBlock;
60
+ const blockEnd = (i + 1) * perBlock;
61
+
62
+ if (safePercent >= blockEnd) {
63
+ bar += "█"; // 완전 채움
64
+ } else if (safePercent > blockStart) {
65
+ // 프론티어: 구간 내 진행률
66
+ const progress = (safePercent - blockStart) / perBlock;
67
+ if (progress >= 0.75) bar += "▓";
68
+ else if (progress >= 0.33) bar += "▒";
69
+ else bar += "░";
70
+ } else {
71
+ bar += "░"; // 미도달
72
+ }
73
+ }
74
+
75
+ // 채워진 부분 = barColor, 빈 부분 = DIM
76
+ const filledEnd = Math.ceil(safePercent / perBlock);
77
+ const coloredPart = barColor + bar.slice(0, filledEnd) + RESET;
78
+ const dimPart = filledEnd < width ? DIM + bar.slice(filledEnd) + RESET : "";
79
+
80
+ return coloredPart + dimPart;
81
+ }
82
+
83
+ // 프로바이더별 색상 % (< 70%: 프로바이더 색, ≥ 70%: 경고색)
84
+ export function colorByProvider(value, text, providerColorFn) {
85
+ if (value >= 85) return red(text);
86
+ if (value >= 70) return yellow(text);
87
+ return providerColorFn(text);
88
+ }