triflux 10.3.4 → 10.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/LICENSE +21 -21
  2. package/bin/tfx-doctor-tui.mjs +1 -1
  3. package/bin/tfx-doctor.mjs +6 -1
  4. package/bin/tfx-profile.mjs +1 -1
  5. package/bin/tfx-setup-tui.mjs +1 -1
  6. package/bin/tfx-setup.mjs +6 -1
  7. package/bin/triflux.mjs +2396 -1140
  8. package/hooks/agent-route-guard.mjs +12 -8
  9. package/hooks/cross-review-tracker.mjs +21 -8
  10. package/hooks/error-context.mjs +19 -7
  11. package/hooks/hook-adaptive-collector.mjs +18 -16
  12. package/hooks/hook-manager.mjs +93 -32
  13. package/hooks/hook-orchestrator.mjs +108 -24
  14. package/hooks/hook-registry.json +11 -0
  15. package/hooks/keyword-rules.json +6 -10
  16. package/hooks/lib/resolve-root.mjs +1 -1
  17. package/hooks/mcp-config-watcher.mjs +6 -2
  18. package/hooks/pipeline-stop.mjs +3 -6
  19. package/hooks/safety-guard.mjs +99 -28
  20. package/hooks/session-start-fast.mjs +143 -0
  21. package/hooks/subagent-verifier.mjs +5 -4
  22. package/hub/account-broker.mjs +256 -60
  23. package/hub/adaptive-diagnostic.mjs +75 -48
  24. package/hub/adaptive-inject.mjs +95 -57
  25. package/hub/adaptive-memory.mjs +156 -42
  26. package/hub/adaptive.mjs +60 -31
  27. package/hub/assign-callbacks.mjs +67 -30
  28. package/hub/bridge.mjs +0 -1
  29. package/hub/cli-adapter-base.mjs +200 -48
  30. package/hub/codex-adapter.mjs +76 -96
  31. package/hub/codex-compat.mjs +3 -3
  32. package/hub/codex-preflight.mjs +63 -37
  33. package/hub/delegator/contracts.mjs +19 -23
  34. package/hub/delegator/index.mjs +3 -3
  35. package/hub/delegator/service.mjs +88 -64
  36. package/hub/delegator/tool-definitions.mjs +5 -5
  37. package/hub/fullcycle.mjs +33 -17
  38. package/hub/gemini-adapter.mjs +69 -94
  39. package/hub/hitl.mjs +89 -30
  40. package/hub/intent.mjs +161 -38
  41. package/hub/lib/cache-guard.mjs +43 -17
  42. package/hub/lib/mcp-response-cache.mjs +66 -32
  43. package/hub/lib/memory-store.mjs +285 -111
  44. package/hub/lib/path-utils.mjs +35 -37
  45. package/hub/lib/process-utils.mjs +106 -37
  46. package/hub/lib/spawn-trace.mjs +527 -0
  47. package/hub/lib/ssh-command.mjs +34 -4
  48. package/hub/lib/ssh-retry.mjs +5 -1
  49. package/hub/lib/uuidv7.mjs +4 -3
  50. package/hub/memory-doctor.mjs +266 -106
  51. package/hub/middleware/request-logger.mjs +61 -34
  52. package/hub/paths.mjs +9 -9
  53. package/hub/pipeline/gates/confidence.mjs +34 -15
  54. package/hub/pipeline/gates/consensus.mjs +27 -15
  55. package/hub/pipeline/gates/index.mjs +7 -3
  56. package/hub/pipeline/gates/selfcheck.mjs +57 -19
  57. package/hub/pipeline/index.mjs +77 -42
  58. package/hub/pipeline/state.mjs +10 -10
  59. package/hub/pipeline/transitions.mjs +40 -23
  60. package/hub/platform.mjs +57 -48
  61. package/hub/promote-penalties.mjs +25 -7
  62. package/hub/quality/deslop.mjs +70 -49
  63. package/hub/research.mjs +32 -25
  64. package/hub/router.mjs +240 -107
  65. package/hub/routing/complexity.mjs +132 -29
  66. package/hub/routing/index.mjs +17 -12
  67. package/hub/routing/q-learning.mjs +76 -28
  68. package/hub/server.mjs +4 -4
  69. package/hub/session-fingerprint.mjs +126 -60
  70. package/hub/state.mjs +84 -43
  71. package/hub/store-adapter.mjs +59 -26
  72. package/hub/store.mjs +356 -153
  73. package/hub/team/agent-map.json +22 -7
  74. package/hub/team/ansi.mjs +186 -122
  75. package/hub/team/backend.mjs +28 -10
  76. package/hub/team/cli/commands/attach.mjs +29 -9
  77. package/hub/team/cli/commands/control.mjs +29 -8
  78. package/hub/team/cli/commands/debug.mjs +32 -11
  79. package/hub/team/cli/commands/focus.mjs +38 -11
  80. package/hub/team/cli/commands/interrupt.mjs +18 -6
  81. package/hub/team/cli/commands/kill.mjs +16 -5
  82. package/hub/team/cli/commands/list.mjs +11 -4
  83. package/hub/team/cli/commands/send.mjs +19 -6
  84. package/hub/team/cli/commands/start/index.mjs +154 -31
  85. package/hub/team/cli/commands/start/parse-args.mjs +38 -11
  86. package/hub/team/cli/commands/start/start-headless.mjs +112 -36
  87. package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
  88. package/hub/team/cli/commands/start/start-mux.mjs +70 -21
  89. package/hub/team/cli/commands/start/start-wt.mjs +29 -12
  90. package/hub/team/cli/commands/status.mjs +43 -14
  91. package/hub/team/cli/commands/stop.mjs +11 -4
  92. package/hub/team/cli/commands/task.mjs +8 -3
  93. package/hub/team/cli/commands/tasks.mjs +1 -1
  94. package/hub/team/cli/index.mjs +2 -2
  95. package/hub/team/cli/manifest.mjs +38 -8
  96. package/hub/team/cli/render.mjs +30 -8
  97. package/hub/team/cli/services/attach-fallback.mjs +31 -11
  98. package/hub/team/cli/services/hub-client.mjs +42 -14
  99. package/hub/team/cli/services/member-selector.mjs +11 -4
  100. package/hub/team/cli/services/native-control.mjs +48 -21
  101. package/hub/team/cli/services/runtime-mode.mjs +2 -1
  102. package/hub/team/cli/services/state-store.mjs +25 -8
  103. package/hub/team/cli/services/task-model.mjs +16 -6
  104. package/hub/team/conductor-mesh-bridge.mjs +24 -23
  105. package/hub/team/conductor.mjs +8 -4
  106. package/hub/team/dashboard-anchor.mjs +4 -5
  107. package/hub/team/dashboard-layout.mjs +3 -1
  108. package/hub/team/dashboard-open.mjs +41 -21
  109. package/hub/team/dashboard.mjs +76 -28
  110. package/hub/team/event-log.mjs +18 -10
  111. package/hub/team/handoff.mjs +31 -15
  112. package/hub/team/headless.mjs +2 -1
  113. package/hub/team/health-probe.mjs +69 -54
  114. package/hub/team/launcher-template.mjs +16 -13
  115. package/hub/team/native-supervisor.mjs +65 -21
  116. package/hub/team/native.mjs +74 -35
  117. package/hub/team/nativeProxy.mjs +184 -113
  118. package/hub/team/notify.mjs +119 -76
  119. package/hub/team/orchestrator.mjs +9 -4
  120. package/hub/team/pane.mjs +12 -7
  121. package/hub/team/process-cleanup.mjs +25 -16
  122. package/hub/team/psmux.mjs +491 -201
  123. package/hub/team/remote-probe.mjs +68 -52
  124. package/hub/team/remote-session.mjs +117 -59
  125. package/hub/team/remote-watcher.mjs +61 -33
  126. package/hub/team/routing.mjs +51 -25
  127. package/hub/team/runtime-strategy.mjs +3 -1
  128. package/hub/team/session.mjs +98 -34
  129. package/hub/team/staleState.mjs +72 -30
  130. package/hub/team/swarm-locks.mjs +15 -13
  131. package/hub/team/swarm-planner.mjs +32 -21
  132. package/hub/team/swarm-reconciler.mjs +48 -23
  133. package/hub/team/tui-lite.mjs +266 -68
  134. package/hub/team/tui-remote-adapter.mjs +14 -10
  135. package/hub/team/tui-viewer.mjs +99 -43
  136. package/hub/team/tui.mjs +708 -271
  137. package/hub/team/worktree-lifecycle.mjs +152 -58
  138. package/hub/team/wt-manager.mjs +24 -14
  139. package/hub/token-mode.mjs +71 -71
  140. package/hub/tray.mjs +66 -23
  141. package/hub/workers/claude-worker.mjs +162 -118
  142. package/hub/workers/codex-mcp.mjs +192 -141
  143. package/hub/workers/delegator-mcp.mjs +507 -333
  144. package/hub/workers/factory.mjs +8 -8
  145. package/hub/workers/gemini-worker.mjs +115 -84
  146. package/hub/workers/interface.mjs +6 -1
  147. package/hub/workers/worker-utils.mjs +21 -14
  148. package/hud/colors.mjs +27 -9
  149. package/hud/constants.mjs +162 -26
  150. package/hud/context-monitor.mjs +82 -41
  151. package/hud/hud-qos-status.mjs +129 -49
  152. package/hud/mission-board.mjs +6 -3
  153. package/hud/providers/claude.mjs +226 -115
  154. package/hud/providers/codex.mjs +62 -22
  155. package/hud/providers/gemini.mjs +168 -56
  156. package/hud/renderers.mjs +384 -119
  157. package/hud/terminal.mjs +101 -31
  158. package/hud/utils.mjs +78 -38
  159. package/mesh/index.mjs +11 -5
  160. package/mesh/mesh-budget.mjs +18 -9
  161. package/mesh/mesh-heartbeat.mjs +1 -1
  162. package/mesh/mesh-queue.mjs +3 -5
  163. package/mesh/mesh-router.mjs +5 -4
  164. package/package.json +2 -1
  165. package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
  166. package/scripts/__tests__/keyword-detector.test.mjs +77 -28
  167. package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
  168. package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
  169. package/scripts/__tests__/remote-spawn.test.mjs +10 -4
  170. package/scripts/__tests__/session-start-fast.test.mjs +36 -0
  171. package/scripts/__tests__/skill-template.test.mjs +98 -50
  172. package/scripts/__tests__/smoke.test.mjs +1 -1
  173. package/scripts/__tests__/spawn-trace.test.mjs +102 -0
  174. package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
  175. package/scripts/cache-doctor.mjs +11 -4
  176. package/scripts/cache-warmup.mjs +96 -37
  177. package/scripts/claudemd-sync.mjs +27 -17
  178. package/scripts/codex-gateway-preflight.mjs +52 -37
  179. package/scripts/codex-mcp-gateway-sync.mjs +59 -39
  180. package/scripts/completions/tfx.bash +47 -47
  181. package/scripts/completions/tfx.fish +44 -44
  182. package/scripts/completions/tfx.zsh +83 -83
  183. package/scripts/config-audit.mjs +232 -0
  184. package/scripts/convert-to-tmpl.mjs +54 -0
  185. package/scripts/cross-review-gate.mjs +35 -12
  186. package/scripts/cross-review-tracker.mjs +21 -8
  187. package/scripts/demo.mjs +35 -17
  188. package/scripts/doctor-diagnose.mjs +284 -0
  189. package/scripts/gen-skill-docs.mjs +7 -2
  190. package/scripts/gen-skill-manifest.mjs +2 -1
  191. package/scripts/headless-guard.mjs +86 -48
  192. package/scripts/hub-ensure.mjs +45 -26
  193. package/scripts/keyword-detector.mjs +41 -20
  194. package/scripts/keyword-rules-expander.mjs +47 -30
  195. package/scripts/lib/claudemd-scanner.mjs +6 -1
  196. package/scripts/lib/context.mjs +3 -3
  197. package/scripts/lib/cross-review-utils.mjs +6 -3
  198. package/scripts/lib/env-probe.mjs +47 -28
  199. package/scripts/lib/gemini-profiles.mjs +44 -10
  200. package/scripts/lib/handoff.mjs +33 -17
  201. package/scripts/lib/hook-utils.mjs +8 -6
  202. package/scripts/lib/keyword-rules.mjs +43 -19
  203. package/scripts/lib/logger.mjs +24 -24
  204. package/scripts/lib/mcp-filter.mjs +377 -239
  205. package/scripts/lib/mcp-guard-engine.mjs +194 -79
  206. package/scripts/lib/mcp-manifest.mjs +23 -13
  207. package/scripts/lib/mcp-server-catalog.mjs +300 -63
  208. package/scripts/lib/psmux-info.mjs +11 -6
  209. package/scripts/lib/remote-spawn-transfer.mjs +44 -14
  210. package/scripts/lib/skill-template.mjs +30 -7
  211. package/scripts/mcp-check.mjs +58 -39
  212. package/scripts/mcp-gateway-config.mjs +83 -39
  213. package/scripts/mcp-gateway-ensure.mjs +43 -35
  214. package/scripts/mcp-gateway-integration-test.mjs +70 -58
  215. package/scripts/mcp-gateway-start.mjs +126 -60
  216. package/scripts/mcp-gateway-verify.mjs +24 -22
  217. package/scripts/mcp-safety-guard.mjs +44 -11
  218. package/scripts/notion-read.mjs +199 -84
  219. package/scripts/pack.mjs +94 -89
  220. package/scripts/preflight-cache.mjs +27 -10
  221. package/scripts/preinstall.mjs +42 -13
  222. package/scripts/remote-spawn.mjs +309 -94
  223. package/scripts/run.cjs +8 -5
  224. package/scripts/session-spawn-helper.mjs +130 -39
  225. package/scripts/session-stale-cleanup.mjs +123 -0
  226. package/scripts/setup.mjs +941 -492
  227. package/scripts/test-lock.mjs +20 -7
  228. package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
  229. package/scripts/tfx-batch-stats.mjs +32 -11
  230. package/scripts/tfx-gate-activate.mjs +11 -4
  231. package/scripts/tfx-route-post.mjs +87 -20
  232. package/scripts/tfx-route-worker.mjs +57 -51
  233. package/scripts/tfx-route.sh +41 -124
  234. package/scripts/tmp-cleanup.mjs +21 -7
  235. package/scripts/token-snapshot.mjs +204 -85
  236. package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
  237. package/skills/.omc/state/idle-notif-cooldown.json +3 -0
  238. package/skills/.omc/state/last-tool-error.json +7 -0
  239. package/skills/.omc/state/subagent-tracking.json +7 -0
  240. package/skills/_templates/base.md +1 -6
  241. package/skills/merge-worktree/SKILL.md.tmpl +144 -0
  242. package/skills/shared/telemetry-segment.md +6 -0
  243. package/skills/star-prompt/SKILL.md.tmpl +222 -0
  244. package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
  245. package/skills/tfx-analysis/skill.json +1 -6
  246. package/skills/tfx-auto/SKILL.md +1 -0
  247. package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
  248. package/skills/tfx-auto-codex/skill.json +1 -3
  249. package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
  250. package/skills/tfx-autopilot/skill.json +1 -5
  251. package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
  252. package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
  253. package/skills/tfx-autoroute/skill.json +1 -7
  254. package/skills/tfx-codex/SKILL.md +1 -0
  255. package/skills/tfx-codex/skill.json +1 -3
  256. package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
  257. package/skills/tfx-codex-swarm/evals/evals.json +1 -1
  258. package/skills/tfx-codex-swarm/skill.json +1 -4
  259. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
  260. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
  261. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
  262. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
  263. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
  264. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
  265. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
  266. package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
  267. package/skills/tfx-debate/SKILL.md.tmpl +192 -0
  268. package/skills/tfx-debate/skill.json +1 -7
  269. package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
  270. package/skills/tfx-deep-analysis/skill.json +1 -5
  271. package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
  272. package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
  273. package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
  274. package/skills/tfx-deep-qa/skill.json +1 -6
  275. package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
  276. package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
  277. package/skills/tfx-doctor/SKILL.md +21 -0
  278. package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
  279. package/skills/tfx-doctor/skill.json +1 -3
  280. package/skills/tfx-find/SKILL.md +1 -0
  281. package/skills/tfx-forge/SKILL.md.tmpl +187 -0
  282. package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
  283. package/skills/tfx-fullcycle/skill.json +1 -6
  284. package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
  285. package/skills/tfx-gemini/skill.json +1 -3
  286. package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
  287. package/skills/tfx-hooks/skill.json +1 -3
  288. package/skills/tfx-hub/SKILL.md.tmpl +212 -0
  289. package/skills/tfx-hub/skill.json +1 -3
  290. package/skills/tfx-index/SKILL.md +1 -0
  291. package/skills/tfx-index/skill.json +1 -6
  292. package/skills/tfx-interview/SKILL.md.tmpl +285 -0
  293. package/skills/tfx-multi/SKILL.md.tmpl +183 -0
  294. package/skills/tfx-multi/skill.json +1 -3
  295. package/skills/tfx-panel/SKILL.md.tmpl +189 -0
  296. package/skills/tfx-panel/skill.json +1 -7
  297. package/skills/tfx-persist/SKILL.md.tmpl +270 -0
  298. package/skills/tfx-persist/skill.json +1 -7
  299. package/skills/tfx-plan/SKILL.md +1 -0
  300. package/skills/tfx-plan/skill.json +1 -6
  301. package/skills/tfx-profile/SKILL.md.tmpl +239 -0
  302. package/skills/tfx-profile/skill.json +1 -3
  303. package/skills/tfx-prune/SKILL.md.tmpl +200 -0
  304. package/skills/tfx-prune/skill.json +1 -7
  305. package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
  306. package/skills/tfx-psmux-rules/skill.json +1 -4
  307. package/skills/tfx-qa/SKILL.md +1 -0
  308. package/skills/tfx-qa/skill.json +1 -6
  309. package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
  310. package/skills/tfx-ralph/skill.json +1 -4
  311. package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
  312. package/skills/tfx-remote-setup/skill.json +1 -3
  313. package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
  314. package/skills/tfx-remote-spawn/references/hosts.json +16 -0
  315. package/skills/tfx-remote-spawn/skill.json +1 -4
  316. package/skills/tfx-research/SKILL.md +1 -0
  317. package/skills/tfx-review/SKILL.md +1 -0
  318. package/skills/tfx-review/skill.json +1 -6
  319. package/skills/tfx-setup/SKILL.md.tmpl +504 -0
  320. package/skills/tfx-setup/skill.json +1 -3
  321. package/skills/tfx-swarm/SKILL.md +22 -0
  322. package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
  323. package/tui/codex-profile.mjs +88 -33
  324. package/tui/core.mjs +45 -15
  325. package/tui/doctor.mjs +75 -28
  326. package/tui/gemini-profile.mjs +74 -29
  327. package/tui/monitor-data.mjs +8 -4
  328. package/tui/monitor.mjs +71 -27
  329. package/tui/setup.mjs +133 -42
@@ -1,17 +1,17 @@
1
1
  // hub/workers/codex-mcp.mjs — Codex MCP 서버 래퍼
2
- import process from 'node:process';
3
- import { fileURLToPath } from 'node:url';
2
+ import process from "node:process";
3
+ import { fileURLToPath } from "node:url";
4
4
 
5
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
6
- import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
5
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
7
7
 
8
8
  import {
9
9
  CODEX_MCP_EXECUTION_EXIT_CODE,
10
10
  CODEX_MCP_TRANSPORT_EXIT_CODE,
11
- } from '../cli-adapter-base.mjs';
12
- import { withRetry } from './worker-utils.mjs';
11
+ } from "../cli-adapter-base.mjs";
12
+ import { withRetry } from "./worker-utils.mjs";
13
13
 
14
- const REQUIRED_TOOLS = ['codex', 'codex-reply'];
14
+ const REQUIRED_TOOLS = ["codex", "codex-reply"];
15
15
 
16
16
  export { CODEX_MCP_EXECUTION_EXIT_CODE, CODEX_MCP_TRANSPORT_EXIT_CODE };
17
17
  export const DEFAULT_CODEX_MCP_TIMEOUT_MS = 10 * 60 * 1000;
@@ -29,36 +29,38 @@ export class CodexMcpTransportError extends Error {
29
29
  */
30
30
  constructor(message, options = {}) {
31
31
  super(message, { cause: options.cause });
32
- this.name = 'CodexMcpTransportError';
33
- this.stderr = options.stderr || '';
32
+ this.name = "CodexMcpTransportError";
33
+ this.stderr = options.stderr || "";
34
34
  }
35
35
  }
36
36
 
37
37
  function cloneEnv(env = process.env) {
38
38
  return Object.fromEntries(
39
- Object.entries(env).filter(([, value]) => typeof value === 'string'),
39
+ Object.entries(env).filter(([, value]) => typeof value === "string"),
40
40
  );
41
41
  }
42
42
 
43
43
  function collectTextContent(content = []) {
44
44
  return content
45
- .filter((item) => item?.type === 'text' && typeof item.text === 'string')
45
+ .filter((item) => item?.type === "text" && typeof item.text === "string")
46
46
  .map((item) => item.text)
47
- .join('\n')
47
+ .join("\n")
48
48
  .trim();
49
49
  }
50
50
 
51
- function normalizeStructuredContent(structuredContent, fallbackText = '') {
52
- if (!structuredContent || typeof structuredContent !== 'object') {
51
+ function normalizeStructuredContent(structuredContent, fallbackText = "") {
52
+ if (!structuredContent || typeof structuredContent !== "object") {
53
53
  return { threadId: null, content: fallbackText };
54
54
  }
55
55
 
56
- const threadId = typeof structuredContent.threadId === 'string'
57
- ? structuredContent.threadId
58
- : null;
59
- const content = typeof structuredContent.content === 'string'
60
- ? structuredContent.content
61
- : fallbackText;
56
+ const threadId =
57
+ typeof structuredContent.threadId === "string"
58
+ ? structuredContent.threadId
59
+ : null;
60
+ const content =
61
+ typeof structuredContent.content === "string"
62
+ ? structuredContent.content
63
+ : fallbackText;
62
64
 
63
65
  return { threadId, content };
64
66
  }
@@ -66,29 +68,34 @@ function normalizeStructuredContent(structuredContent, fallbackText = '') {
66
68
  function buildCodexArguments(prompt, opts = {}) {
67
69
  const args = { prompt };
68
70
 
69
- if (typeof opts.cwd === 'string' && opts.cwd) args.cwd = opts.cwd;
70
- if (typeof opts.model === 'string' && opts.model) args.model = opts.model;
71
- if (typeof opts.profile === 'string' && opts.profile) args.profile = opts.profile;
72
- if (typeof opts.approvalPolicy === 'string' && opts.approvalPolicy) {
73
- args['approval-policy'] = opts.approvalPolicy;
71
+ if (typeof opts.cwd === "string" && opts.cwd) args.cwd = opts.cwd;
72
+ if (typeof opts.model === "string" && opts.model) args.model = opts.model;
73
+ if (typeof opts.profile === "string" && opts.profile)
74
+ args.profile = opts.profile;
75
+ if (typeof opts.approvalPolicy === "string" && opts.approvalPolicy) {
76
+ args["approval-policy"] = opts.approvalPolicy;
74
77
  }
75
- if (typeof opts.sandbox === 'string' && opts.sandbox) args.sandbox = opts.sandbox;
76
- if (opts.config && typeof opts.config === 'object') args.config = opts.config;
77
- if (typeof opts.baseInstructions === 'string' && opts.baseInstructions) {
78
- args['base-instructions'] = opts.baseInstructions;
78
+ if (typeof opts.sandbox === "string" && opts.sandbox)
79
+ args.sandbox = opts.sandbox;
80
+ if (opts.config && typeof opts.config === "object") args.config = opts.config;
81
+ if (typeof opts.baseInstructions === "string" && opts.baseInstructions) {
82
+ args["base-instructions"] = opts.baseInstructions;
79
83
  }
80
- if (typeof opts.developerInstructions === 'string' && opts.developerInstructions) {
81
- args['developer-instructions'] = opts.developerInstructions;
84
+ if (
85
+ typeof opts.developerInstructions === "string" &&
86
+ opts.developerInstructions
87
+ ) {
88
+ args["developer-instructions"] = opts.developerInstructions;
82
89
  }
83
- if (typeof opts.compactPrompt === 'string' && opts.compactPrompt) {
84
- args['compact-prompt'] = opts.compactPrompt;
90
+ if (typeof opts.compactPrompt === "string" && opts.compactPrompt) {
91
+ args["compact-prompt"] = opts.compactPrompt;
85
92
  }
86
93
 
87
94
  return args;
88
95
  }
89
96
 
90
97
  function pickToolName(threadId) {
91
- return threadId ? 'codex-reply' : 'codex';
98
+ return threadId ? "codex-reply" : "codex";
92
99
  }
93
100
 
94
101
  function withTimeout(promise, timeoutMs, message) {
@@ -110,27 +117,38 @@ function withTimeout(promise, timeoutMs, message) {
110
117
  }
111
118
 
112
119
  function normalizeRetryOptions(retryOptions) {
113
- if (!retryOptions || typeof retryOptions !== 'object') {
120
+ if (!retryOptions || typeof retryOptions !== "object") {
114
121
  return Object.freeze({});
115
122
  }
116
123
  return Object.freeze({ ...retryOptions });
117
124
  }
118
125
 
119
126
  function isCodexRetryable(error) {
120
- return error instanceof CodexMcpTransportError
121
- || error?.code === 'ETIMEDOUT'
122
- || error?.cause?.code === 'ETIMEDOUT';
127
+ return (
128
+ error instanceof CodexMcpTransportError ||
129
+ error?.code === "ETIMEDOUT" ||
130
+ error?.cause?.code === "ETIMEDOUT"
131
+ );
123
132
  }
124
133
 
125
- function detectWorkerCategory(error, fallbackCategory = 'transient') {
126
- const combined = `${error?.message || ''}\n${error?.stderr || ''}`.toLowerCase();
127
-
128
- if (error?.code === 'INVALID_INPUT') return 'input';
129
- if (/(unauthorized|forbidden|auth|login|token|credential|apikey|api key)/i.test(combined)) {
130
- return 'auth';
134
+ function detectWorkerCategory(error, fallbackCategory = "transient") {
135
+ const combined =
136
+ `${error?.message || ""}\n${error?.stderr || ""}`.toLowerCase();
137
+
138
+ if (error?.code === "INVALID_INPUT") return "input";
139
+ if (
140
+ /(unauthorized|forbidden|auth|login|token|credential|apikey|api key)/i.test(
141
+ combined,
142
+ )
143
+ ) {
144
+ return "auth";
131
145
  }
132
- if (/(config|unknown option|invalid option|missing|필수 mcp 도구 누락)/i.test(combined)) {
133
- return 'config';
146
+ if (
147
+ /(config|unknown option|invalid option|missing|필수 mcp 도구 누락)/i.test(
148
+ combined,
149
+ )
150
+ ) {
151
+ return "config";
134
152
  }
135
153
 
136
154
  return fallbackCategory;
@@ -138,20 +156,25 @@ function detectWorkerCategory(error, fallbackCategory = 'transient') {
138
156
 
139
157
  function buildCodexErrorInfo(error, attempts) {
140
158
  const retryable = isCodexRetryable(error);
141
- const code = error instanceof CodexMcpTransportError
142
- ? 'CODEX_TRANSPORT_ERROR'
143
- : (error?.code || 'CODEX_EXECUTION_ERROR');
144
- const category = detectWorkerCategory(error, retryable ? 'transient' : 'config');
145
-
146
- let recovery = 'Review the Codex worker error output and retry after correcting the issue.';
147
- if (code === 'INVALID_INPUT') {
148
- recovery = 'Provide a non-empty prompt before invoking the Codex worker.';
159
+ const code =
160
+ error instanceof CodexMcpTransportError
161
+ ? "CODEX_TRANSPORT_ERROR"
162
+ : error?.code || "CODEX_EXECUTION_ERROR";
163
+ const category = detectWorkerCategory(
164
+ error,
165
+ retryable ? "transient" : "config",
166
+ );
167
+
168
+ let recovery =
169
+ "Review the Codex worker error output and retry after correcting the issue.";
170
+ if (code === "INVALID_INPUT") {
171
+ recovery = "Provide a non-empty prompt before invoking the Codex worker.";
149
172
  } else if (retryable) {
150
- recovery = 'Retry after reconnecting the Codex MCP transport.';
151
- } else if (category === 'auth') {
152
- recovery = 'Refresh the Codex authentication state and retry.';
153
- } else if (category === 'config') {
154
- recovery = 'Check the Codex MCP configuration and available tools.';
173
+ recovery = "Retry after reconnecting the Codex MCP transport.";
174
+ } else if (category === "auth") {
175
+ recovery = "Refresh the Codex authentication state and retry.";
176
+ } else if (category === "config") {
177
+ recovery = "Check the Codex MCP configuration and available tools.";
155
178
  }
156
179
 
157
180
  return Object.freeze({
@@ -167,7 +190,7 @@ function buildCodexErrorInfo(error, attempts) {
167
190
  * Codex MCP 워커
168
191
  */
169
192
  export class CodexMcpWorker {
170
- type = 'codex';
193
+ type = "codex";
171
194
 
172
195
  /**
173
196
  * @param {object} [options]
@@ -179,13 +202,17 @@ export class CodexMcpWorker {
179
202
  * @param {number} [options.bootstrapTimeoutMs]
180
203
  */
181
204
  constructor(options = {}) {
182
- this.command = options.command || process.env.CODEX_BIN || 'codex';
183
- this.args = Array.isArray(options.args) && options.args.length
184
- ? [...options.args]
185
- : ['mcp-server'];
205
+ this.command = options.command || process.env.CODEX_BIN || "codex";
206
+ this.args =
207
+ Array.isArray(options.args) && options.args.length
208
+ ? [...options.args]
209
+ : ["mcp-server"];
186
210
  this.cwd = options.cwd || process.cwd();
187
211
  this.env = cloneEnv({ ...cloneEnv(process.env), ...cloneEnv(options.env) });
188
- this.clientInfo = options.clientInfo || { name: 'triflux-codex-mcp', version: '1.0.0' };
212
+ this.clientInfo = options.clientInfo || {
213
+ name: "triflux-codex-mcp",
214
+ version: "1.0.0",
215
+ };
189
216
  this.bootstrapTimeoutMs = Number.isFinite(options.bootstrapTimeoutMs)
190
217
  ? options.bootstrapTimeoutMs
191
218
  : DEFAULT_CODEX_MCP_BOOTSTRAP_TIMEOUT_MS;
@@ -196,7 +223,7 @@ export class CodexMcpWorker {
196
223
  this.ready = false;
197
224
  this.availableTools = new Set();
198
225
  this.threadIds = new Map();
199
- this.serverStderr = '';
226
+ this.serverStderr = "";
200
227
  }
201
228
 
202
229
  isReady() {
@@ -227,12 +254,12 @@ export class CodexMcpWorker {
227
254
  args: this.args,
228
255
  cwd: this.cwd,
229
256
  env: this.env,
230
- stderr: 'pipe',
257
+ stderr: "pipe",
231
258
  });
232
259
  const client = new Client(this.clientInfo, { capabilities: {} });
233
260
 
234
- this.serverStderr = '';
235
- transport.stderr?.on('data', (chunk) => {
261
+ this.serverStderr = "";
262
+ transport.stderr?.on("data", (chunk) => {
236
263
  this.serverStderr += String(chunk);
237
264
  if (this.serverStderr.length > 16000) {
238
265
  this.serverStderr = this.serverStderr.slice(-16000);
@@ -240,17 +267,23 @@ export class CodexMcpWorker {
240
267
  });
241
268
 
242
269
  try {
243
- await withTimeout((async () => {
244
- await client.connect(transport);
245
- const tools = await client.listTools(undefined, { timeout: this.bootstrapTimeoutMs });
246
- this.availableTools = new Set(tools.tools.map((tool) => tool.name));
247
-
248
- for (const requiredTool of REQUIRED_TOOLS) {
249
- if (!this.availableTools.has(requiredTool)) {
250
- throw new Error(`필수 MCP 도구 누락: ${requiredTool}`);
270
+ await withTimeout(
271
+ (async () => {
272
+ await client.connect(transport);
273
+ const tools = await client.listTools(undefined, {
274
+ timeout: this.bootstrapTimeoutMs,
275
+ });
276
+ this.availableTools = new Set(tools.tools.map((tool) => tool.name));
277
+
278
+ for (const requiredTool of REQUIRED_TOOLS) {
279
+ if (!this.availableTools.has(requiredTool)) {
280
+ throw new Error(`필수 MCP 도구 누락: ${requiredTool}`);
281
+ }
251
282
  }
252
- }
253
- })(), this.bootstrapTimeoutMs, `Codex MCP bootstrap timeout (${this.bootstrapTimeoutMs}ms)`);
283
+ })(),
284
+ this.bootstrapTimeoutMs,
285
+ `Codex MCP bootstrap timeout (${this.bootstrapTimeoutMs}ms)`,
286
+ );
254
287
  } catch (error) {
255
288
  await client.close().catch(() => {});
256
289
  transport.stderr?.destroy?.();
@@ -289,62 +322,78 @@ export class CodexMcpWorker {
289
322
  * @returns {Promise<import('./interface.mjs').WorkerResult>}
290
323
  */
291
324
  async execute(prompt, opts = {}) {
292
- if (typeof prompt !== 'string' || !prompt.trim()) {
325
+ if (typeof prompt !== "string" || !prompt.trim()) {
293
326
  return {
294
- output: 'prompt는 비어 있을 수 없습니다.',
327
+ output: "prompt는 비어 있을 수 없습니다.",
295
328
  exitCode: CODEX_MCP_EXECUTION_EXIT_CODE,
296
329
  threadId: null,
297
330
  sessionKey: opts.sessionKey || null,
298
- error: buildCodexErrorInfo({ code: 'INVALID_INPUT', message: 'prompt는 비어 있을 수 없습니다.' }, 0),
331
+ error: buildCodexErrorInfo(
332
+ { code: "INVALID_INPUT", message: "prompt는 비어 있을 수 없습니다." },
333
+ 0,
334
+ ),
299
335
  raw: null,
300
336
  };
301
337
  }
302
338
 
303
- const sessionKey = typeof opts.sessionKey === 'string' && opts.sessionKey
304
- ? opts.sessionKey
305
- : null;
339
+ const sessionKey =
340
+ typeof opts.sessionKey === "string" && opts.sessionKey
341
+ ? opts.sessionKey
342
+ : null;
306
343
 
307
344
  if (opts.resetSession && sessionKey) {
308
345
  this.clearThread(sessionKey);
309
346
  }
310
347
 
311
- const threadId = typeof opts.threadId === 'string' && opts.threadId
312
- ? opts.threadId
313
- : (sessionKey ? this.getThreadId(sessionKey) : null);
314
- const timeoutMs = Number.isFinite(opts.timeoutMs) ? opts.timeoutMs : DEFAULT_CODEX_MCP_TIMEOUT_MS;
348
+ const threadId =
349
+ typeof opts.threadId === "string" && opts.threadId
350
+ ? opts.threadId
351
+ : sessionKey
352
+ ? this.getThreadId(sessionKey)
353
+ : null;
354
+ const timeoutMs = Number.isFinite(opts.timeoutMs)
355
+ ? opts.timeoutMs
356
+ : DEFAULT_CODEX_MCP_TIMEOUT_MS;
315
357
  let attempts = 0;
316
358
  let activeThreadId = threadId;
317
359
 
318
360
  try {
319
- const { rawResult, normalized } = await withRetry(async () => {
320
- attempts += 1;
321
- if (attempts === 1) {
322
- await this.start();
323
- } else {
324
- await this.stop();
325
- await this.start();
326
- }
327
-
328
- const toolName = pickToolName(activeThreadId);
329
- const toolArguments = toolName === 'codex-reply'
330
- ? { prompt, threadId: activeThreadId }
331
- : buildCodexArguments(prompt, opts);
332
-
333
- const nextRawResult = await this.client.callTool(
334
- { name: toolName, arguments: toolArguments },
335
- undefined,
336
- { timeout: timeoutMs },
337
- );
338
-
339
- const textContent = collectTextContent(nextRawResult.content);
340
- const nextNormalized = normalizeStructuredContent(nextRawResult.structuredContent, textContent);
341
- activeThreadId = nextNormalized.threadId || activeThreadId;
342
-
343
- return { rawResult: nextRawResult, normalized: nextNormalized };
344
- }, {
345
- ...this.retryOptions,
346
- shouldRetry: (error) => isCodexRetryable(error),
347
- });
361
+ const { rawResult, normalized } = await withRetry(
362
+ async () => {
363
+ attempts += 1;
364
+ if (attempts === 1) {
365
+ await this.start();
366
+ } else {
367
+ await this.stop();
368
+ await this.start();
369
+ }
370
+
371
+ const toolName = pickToolName(activeThreadId);
372
+ const toolArguments =
373
+ toolName === "codex-reply"
374
+ ? { prompt, threadId: activeThreadId }
375
+ : buildCodexArguments(prompt, opts);
376
+
377
+ const nextRawResult = await this.client.callTool(
378
+ { name: toolName, arguments: toolArguments },
379
+ undefined,
380
+ { timeout: timeoutMs },
381
+ );
382
+
383
+ const textContent = collectTextContent(nextRawResult.content);
384
+ const nextNormalized = normalizeStructuredContent(
385
+ nextRawResult.structuredContent,
386
+ textContent,
387
+ );
388
+ activeThreadId = nextNormalized.threadId || activeThreadId;
389
+
390
+ return { rawResult: nextRawResult, normalized: nextNormalized };
391
+ },
392
+ {
393
+ ...this.retryOptions,
394
+ shouldRetry: (error) => isCodexRetryable(error),
395
+ },
396
+ );
348
397
 
349
398
  if (sessionKey && normalized.threadId) {
350
399
  this.setThreadId(sessionKey, normalized.threadId);
@@ -357,7 +406,7 @@ export class CodexMcpWorker {
357
406
  threadId: normalized.threadId,
358
407
  sessionKey,
359
408
  error: buildCodexErrorInfo(
360
- { code: 'CODEX_TOOL_ERROR', message: normalized.content },
409
+ { code: "CODEX_TOOL_ERROR", message: normalized.content },
361
410
  attempts,
362
411
  ),
363
412
  raw: rawResult,
@@ -391,7 +440,7 @@ export function createCodexMcpWorker(options = {}) {
391
440
 
392
441
  function parseCliArgs(argv) {
393
442
  const options = {
394
- command: process.env.CODEX_BIN || 'codex',
443
+ command: process.env.CODEX_BIN || "codex",
395
444
  cwd: process.cwd(),
396
445
  timeoutMs: DEFAULT_CODEX_MCP_TIMEOUT_MS,
397
446
  };
@@ -408,49 +457,49 @@ function parseCliArgs(argv) {
408
457
  };
409
458
 
410
459
  switch (token) {
411
- case '--prompt':
460
+ case "--prompt":
412
461
  options.prompt = next();
413
462
  break;
414
- case '--thread-id':
463
+ case "--thread-id":
415
464
  options.threadId = next();
416
465
  break;
417
- case '--session-key':
466
+ case "--session-key":
418
467
  options.sessionKey = next();
419
468
  break;
420
- case '--cwd':
469
+ case "--cwd":
421
470
  options.cwd = next();
422
471
  break;
423
- case '--profile':
472
+ case "--profile":
424
473
  options.profile = next();
425
474
  break;
426
- case '--model':
475
+ case "--model":
427
476
  options.model = next();
428
477
  break;
429
- case '--approval-policy':
478
+ case "--approval-policy":
430
479
  options.approvalPolicy = next();
431
480
  break;
432
- case '--sandbox':
481
+ case "--sandbox":
433
482
  options.sandbox = next();
434
483
  break;
435
- case '--base-instructions':
484
+ case "--base-instructions":
436
485
  options.baseInstructions = next();
437
486
  break;
438
- case '--developer-instructions':
487
+ case "--developer-instructions":
439
488
  options.developerInstructions = next();
440
489
  break;
441
- case '--compact-prompt':
490
+ case "--compact-prompt":
442
491
  options.compactPrompt = next();
443
492
  break;
444
- case '--timeout-ms':
493
+ case "--timeout-ms":
445
494
  options.timeoutMs = Number.parseInt(next(), 10);
446
495
  break;
447
- case '--config-json':
496
+ case "--config-json":
448
497
  options.config = JSON.parse(next());
449
498
  break;
450
- case '--codex-command':
499
+ case "--codex-command":
451
500
  options.command = next();
452
501
  break;
453
- case '--reset-session':
502
+ case "--reset-session":
454
503
  options.resetSession = true;
455
504
  break;
456
505
  default:
@@ -458,8 +507,8 @@ function parseCliArgs(argv) {
458
507
  }
459
508
  }
460
509
 
461
- if (typeof options.prompt !== 'string' || !options.prompt) {
462
- throw new Error('--prompt는 필수입니다.');
510
+ if (typeof options.prompt !== "string" || !options.prompt) {
511
+ throw new Error("--prompt는 필수입니다.");
463
512
  }
464
513
 
465
514
  return options;
@@ -470,7 +519,9 @@ export async function runCodexMcpCli(argv = process.argv.slice(2)) {
470
519
  try {
471
520
  options = parseCliArgs(argv);
472
521
  } catch (error) {
473
- console.error(`[codex-mcp] ${error instanceof Error ? error.message : String(error)}`);
522
+ console.error(
523
+ `[codex-mcp] ${error instanceof Error ? error.message : String(error)}`,
524
+ );
474
525
  process.exitCode = 64;
475
526
  return;
476
527
  }
@@ -484,8 +535,8 @@ export async function runCodexMcpCli(argv = process.argv.slice(2)) {
484
535
  const result = await worker.execute(options.prompt, options);
485
536
  if (result.output) {
486
537
  process.stdout.write(result.output);
487
- if (!result.output.endsWith('\n')) {
488
- process.stdout.write('\n');
538
+ if (!result.output.endsWith("\n")) {
539
+ process.stdout.write("\n");
489
540
  }
490
541
  }
491
542
  process.exitCode = result.exitCode;
@@ -494,7 +545,7 @@ export async function runCodexMcpCli(argv = process.argv.slice(2)) {
494
545
  if (error instanceof CodexMcpTransportError && error.stderr) {
495
546
  lines.push(error.stderr);
496
547
  }
497
- console.error(`[codex-mcp] ${lines.join('\n')}`);
548
+ console.error(`[codex-mcp] ${lines.join("\n")}`);
498
549
  process.exitCode = CODEX_MCP_TRANSPORT_EXIT_CODE;
499
550
  } finally {
500
551
  await worker.stop();