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,28 +1,30 @@
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';
1
+ import { execSync } from "node:child_process";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
5
 
6
- import { whichCommandAsync } from './platform.mjs';
6
+ import { whichCommandAsync } from "./platform.mjs";
7
7
 
8
8
  const MIN_RECOMMENDED_MINOR = 118;
9
9
  let _cachedVersion = null;
10
10
 
11
11
  function escapeRegExp(value) {
12
- return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
12
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13
13
  }
14
14
 
15
- function readConfigText(configPath = join(homedir(), '.codex', 'config.toml')) {
16
- if (!existsSync(configPath)) return '';
15
+ function readConfigText(configPath = join(homedir(), ".codex", "config.toml")) {
16
+ if (!existsSync(configPath)) return "";
17
17
  try {
18
- return readFileSync(configPath, 'utf8');
18
+ return readFileSync(configPath, "utf8");
19
19
  } catch {
20
- return '';
20
+ return "";
21
21
  }
22
22
  }
23
23
 
24
24
  function readTomlString(text, key) {
25
- const match = String(text).match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, 'mu'));
25
+ const match = String(text).match(
26
+ new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]*)"\\s*$`, "mu"),
27
+ );
26
28
  return match?.[1] ?? null;
27
29
  }
28
30
 
@@ -30,13 +32,13 @@ function readSection(text, name) {
30
32
  const lines = String(text).split(/\r?\n/u);
31
33
  const header = `[${name}]`;
32
34
  const start = lines.findIndex((line) => line.trim() === header);
33
- if (start < 0) return '';
35
+ if (start < 0) return "";
34
36
  const body = [];
35
37
  for (const line of lines.slice(start + 1)) {
36
38
  if (/^\s*\[[^\]]+\]\s*$/u.test(line)) break;
37
39
  body.push(line);
38
40
  }
39
- return body.join('\n');
41
+ return body.join("\n");
40
42
  }
41
43
 
42
44
  /**
@@ -47,7 +49,10 @@ function readSection(text, name) {
47
49
  export function getCodexVersion() {
48
50
  if (_cachedVersion !== null) return _cachedVersion;
49
51
  try {
50
- const out = execSync('codex --version', { encoding: 'utf8', timeout: 5000 }).trim();
52
+ const out = execSync("codex --version", {
53
+ encoding: "utf8",
54
+ timeout: 5000,
55
+ }).trim();
51
56
  // "codex 0.117.0" 또는 "0.117.0" 형식 대응
52
57
  const match = out.match(/(\d+)\.(\d+)\.(\d+)/);
53
58
  _cachedVersion = match ? parseInt(match[2], 10) : 0;
@@ -58,29 +63,34 @@ export function getCodexVersion() {
58
63
  }
59
64
 
60
65
  async function checkCodexInstalled() {
61
- const codexPath = await whichCommandAsync('codex');
66
+ const codexPath = await whichCommandAsync("codex");
62
67
  if (codexPath) return { codexPath, ok: true, warnings: [] };
63
68
  return {
64
69
  codexPath: null,
65
70
  ok: false,
66
- warnings: ['Codex CLI not found. Install Codex and ensure `codex` is available on PATH.'],
71
+ warnings: [
72
+ "Codex CLI not found. Install Codex and ensure `codex` is available on PATH.",
73
+ ],
67
74
  };
68
75
  }
69
76
 
70
77
  function checkCodexVersion() {
71
78
  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.`];
79
+ const warnings =
80
+ version >= MIN_RECOMMENDED_MINOR
81
+ ? []
82
+ : [
83
+ `Codex CLI 0.${version}.x detected; 0.${MIN_RECOMMENDED_MINOR}.x or newer is recommended.`,
84
+ ];
75
85
  return { version, warnings };
76
86
  }
77
87
 
78
88
  function checkApprovalMode(configText, opts = {}) {
79
- const approvalMode = readTomlString(configText, 'approval_mode');
80
- const sandbox = readTomlString(configText, 'sandbox');
81
- const subcommand = opts.subcommand || 'exec';
89
+ const approvalMode = readTomlString(configText, "approval_mode");
90
+ const sandbox = readTomlString(configText, "sandbox");
91
+ const subcommand = opts.subcommand || "exec";
82
92
  return {
83
- needsBypass: subcommand === 'exec' || approvalMode !== 'full-auto',
93
+ needsBypass: subcommand === "exec" || approvalMode !== "full-auto",
84
94
  approvalMode,
85
95
  sandbox,
86
96
  };
@@ -88,28 +98,41 @@ function checkApprovalMode(configText, opts = {}) {
88
98
 
89
99
  async function verifyServerHealth(name, configText) {
90
100
  const section = readSection(configText, `mcp_servers.${name}`);
91
- if (!section) return { ok: false, warning: `MCP server '${name}' is not configured.` };
101
+ if (!section)
102
+ return { ok: false, warning: `MCP server '${name}' is not configured.` };
92
103
  if (/^\s*enabled\s*=\s*false\s*$/mu.test(section)) {
93
- return { ok: false, warning: `MCP server '${name}' is disabled in config.toml.` };
104
+ return {
105
+ ok: false,
106
+ warning: `MCP server '${name}' is disabled in config.toml.`,
107
+ };
94
108
  }
95
109
 
96
- const command = readTomlString(section, 'command');
110
+ const command = readTomlString(section, "command");
97
111
  if (command) {
98
112
  const resolved = await whichCommandAsync(command);
99
113
  return resolved
100
- ? { ok: true, warning: '' }
101
- : { ok: false, warning: `MCP server '${name}' command not found: ${command}` };
114
+ ? { ok: true, warning: "" }
115
+ : {
116
+ ok: false,
117
+ warning: `MCP server '${name}' command not found: ${command}`,
118
+ };
102
119
  }
103
120
 
104
- const url = readTomlString(section, 'url');
105
- if (!url || !/^https?:\/\//u.test(url)) return { ok: true, warning: '' };
121
+ const url = readTomlString(section, "url");
122
+ if (!url || !/^https?:\/\//u.test(url)) return { ok: true, warning: "" };
106
123
  try {
107
124
  const response = await fetch(url, { signal: AbortSignal.timeout(2000) });
108
125
  return response.status < 500
109
- ? { ok: true, warning: '' }
110
- : { ok: false, warning: `MCP server '${name}' returned HTTP ${response.status}.` };
126
+ ? { ok: true, warning: "" }
127
+ : {
128
+ ok: false,
129
+ warning: `MCP server '${name}' returned HTTP ${response.status}.`,
130
+ };
111
131
  } catch {
112
- return { ok: false, warning: `MCP server '${name}' is unreachable at ${url}.` };
132
+ return {
133
+ ok: false,
134
+ warning: `MCP server '${name}' is unreachable at ${url}.`,
135
+ };
113
136
  }
114
137
  }
115
138
 
@@ -118,7 +141,7 @@ async function checkMcpHealth(mcpServers, configText) {
118
141
  const warnings = [];
119
142
 
120
143
  for (const name of Array.isArray(mcpServers) ? mcpServers : []) {
121
- const server = String(name ?? '').trim();
144
+ const server = String(name ?? "").trim();
122
145
  if (!server) continue;
123
146
  const result = await verifyServerHealth(server, configText);
124
147
  if (!result.ok) excludeMcpServers.push(server);
@@ -147,10 +170,13 @@ export async function runPreflight(opts = {}) {
147
170
 
148
171
  const configText = readConfigText(opts.configPath);
149
172
  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.`);
173
+ if (approval.approvalMode !== "full-auto") {
174
+ warnings.push(
175
+ `approval_mode is '${approval.approvalMode || "unset"}'; bypass flag will be used.`,
176
+ );
152
177
  }
153
- if (approval.sandbox) warnings.push(`sandbox mode from config.toml: ${approval.sandbox}`);
178
+ if (approval.sandbox)
179
+ warnings.push(`sandbox mode from config.toml: ${approval.sandbox}`);
154
180
 
155
181
  const mcp = await checkMcpHealth(opts.mcpServers, configText);
156
182
  warnings.push(...mcp.warnings);
@@ -1,37 +1,33 @@
1
1
  export const DELEGATOR_MCP_SERVER_INFO = Object.freeze({
2
- name: 'triflux-delegator',
3
- version: '0.1.0',
2
+ name: "triflux-delegator",
3
+ version: "0.1.0",
4
4
  });
5
5
 
6
6
  export const DELEGATOR_TOOL_NAMES = Object.freeze({
7
- delegate: 'delegate',
8
- delegateReply: 'delegate-reply',
9
- status: 'status',
7
+ delegate: "delegate",
8
+ delegateReply: "delegate-reply",
9
+ status: "status",
10
10
  });
11
11
 
12
12
  export const DELEGATOR_PIPE_ACTIONS = Object.freeze({
13
- delegate: 'delegator_delegate',
14
- delegateReply: 'delegator_reply',
15
- status: 'delegator_status',
13
+ delegate: "delegator_delegate",
14
+ delegateReply: "delegator_reply",
15
+ status: "delegator_status",
16
16
  });
17
17
 
18
18
  export const DELEGATOR_JOB_STATUSES = Object.freeze([
19
- 'queued',
20
- 'running',
21
- 'waiting_reply',
22
- 'completed',
23
- 'failed',
19
+ "queued",
20
+ "running",
21
+ "waiting_reply",
22
+ "completed",
23
+ "failed",
24
24
  ]);
25
25
 
26
- export const DELEGATOR_MODES = Object.freeze([
27
- 'sync',
28
- 'async',
29
- ]);
26
+ export const DELEGATOR_MODES = Object.freeze(["sync", "async"]);
30
27
 
31
- export const DELEGATOR_PROVIDERS = Object.freeze([
32
- 'auto',
33
- 'codex',
34
- 'gemini',
35
- ]);
28
+ export const DELEGATOR_PROVIDERS = Object.freeze(["auto", "codex", "gemini"]);
36
29
 
37
- export const DELEGATOR_SCHEMA_URL = new URL('./schema/delegator-tools.schema.json', import.meta.url);
30
+ export const DELEGATOR_SCHEMA_URL = new URL(
31
+ "./schema/delegator-tools.schema.json",
32
+ import.meta.url,
33
+ );
@@ -6,9 +6,9 @@ export {
6
6
  DELEGATOR_PROVIDERS,
7
7
  DELEGATOR_SCHEMA_URL,
8
8
  DELEGATOR_TOOL_NAMES,
9
- } from './contracts.mjs';
10
- export { DelegatorService } from './service.mjs';
9
+ } from "./contracts.mjs";
10
+ export { DelegatorService } from "./service.mjs";
11
11
  export {
12
12
  getDelegatorMcpToolDefinitions,
13
13
  loadDelegatorSchemaBundle,
14
- } from './tool-definitions.mjs';
14
+ } from "./tool-definitions.mjs";
@@ -1,11 +1,11 @@
1
- import { randomUUID } from 'node:crypto';
1
+ import { randomUUID } from "node:crypto";
2
2
 
3
3
  import {
4
4
  DELEGATOR_JOB_STATUSES,
5
5
  DELEGATOR_MODES,
6
6
  DELEGATOR_PROVIDERS,
7
- } from './contracts.mjs';
8
- import { getDelegatorMcpToolDefinitions } from './tool-definitions.mjs';
7
+ } from "./contracts.mjs";
8
+ import { getDelegatorMcpToolDefinitions } from "./tool-definitions.mjs";
9
9
 
10
10
  function deepClone(value) {
11
11
  if (value == null) return value;
@@ -39,28 +39,28 @@ export class DelegatorService {
39
39
  createJobSnapshot(input = {}) {
40
40
  const timestamp = this.now().toISOString();
41
41
  const jobId = input.job_id || this.idFactory();
42
- const mode = input.mode || 'sync';
43
- const providerRequested = input.provider || 'auto';
42
+ const mode = input.mode || "sync";
43
+ const providerRequested = input.provider || "auto";
44
44
 
45
- assertKnown(DELEGATOR_MODES, mode, 'mode');
46
- assertKnown(DELEGATOR_PROVIDERS, providerRequested, 'provider');
45
+ assertKnown(DELEGATOR_MODES, mode, "mode");
46
+ assertKnown(DELEGATOR_PROVIDERS, providerRequested, "provider");
47
47
 
48
48
  return {
49
49
  ok: true,
50
50
  job_id: jobId,
51
- status: 'queued',
51
+ status: "queued",
52
52
  mode,
53
53
  provider_requested: providerRequested,
54
54
  provider_resolved: null,
55
- agent_type: input.agent_type || 'executor',
56
- transport: 'resident-pending',
55
+ agent_type: input.agent_type || "executor",
56
+ transport: "resident-pending",
57
57
  created_at: timestamp,
58
58
  started_at: null,
59
59
  updated_at: timestamp,
60
60
  completed_at: null,
61
- output: '',
62
- stderr: '',
63
- error: '',
61
+ output: "",
62
+ stderr: "",
63
+ error: "",
64
64
  thread_id: input.thread_id || null,
65
65
  session_key: input.session_key || null,
66
66
  conversation_open: false,
@@ -69,9 +69,9 @@ export class DelegatorService {
69
69
 
70
70
  recordJob(snapshot) {
71
71
  if (!snapshot?.job_id) {
72
- throw new Error('job_id is required');
72
+ throw new Error("job_id is required");
73
73
  }
74
- assertKnown(DELEGATOR_JOB_STATUSES, snapshot.status, 'status');
74
+ assertKnown(DELEGATOR_JOB_STATUSES, snapshot.status, "status");
75
75
  this.jobs.set(snapshot.job_id, deepClone(snapshot));
76
76
  return this.getStatusSnapshot(snapshot.job_id);
77
77
  }
@@ -86,19 +86,20 @@ export class DelegatorService {
86
86
  _normalizeInput(input = {}) {
87
87
  return {
88
88
  prompt: input.prompt,
89
- provider: input.provider || 'auto',
90
- mode: input.mode || 'sync',
91
- agent_type: input.agent_type || input.agentType || 'executor',
89
+ provider: input.provider || "auto",
90
+ mode: input.mode || "sync",
91
+ agent_type: input.agent_type || input.agentType || "executor",
92
92
  cwd: input.cwd || null,
93
93
  timeout_ms: input.timeout_ms || input.timeoutMs || null,
94
94
  session_key: input.session_key || input.sessionKey || null,
95
95
  thread_id: input.thread_id || input.threadId || null,
96
96
  reset_session: input.reset_session ?? input.resetSession ?? false,
97
- mcp_profile: input.mcp_profile || input.mcpProfile || 'auto',
97
+ mcp_profile: input.mcp_profile || input.mcpProfile || "auto",
98
98
  search_tool: input.search_tool || input.searchTool || null,
99
99
  context_file: input.context_file || input.contextFile || null,
100
100
  model: input.model || null,
101
- developer_instructions: input.developer_instructions || input.developerInstructions || null,
101
+ developer_instructions:
102
+ input.developer_instructions || input.developerInstructions || null,
102
103
  compact_prompt: input.compact_prompt || input.compactPrompt || null,
103
104
  };
104
105
  }
@@ -131,18 +132,22 @@ export class DelegatorService {
131
132
  const ok = workerResult.ok !== false;
132
133
 
133
134
  snapshot.ok = ok;
134
- snapshot.status = workerResult.status || (ok ? 'completed' : 'failed');
135
- snapshot.provider_resolved = workerResult.providerResolved || workerResult.provider_resolved || null;
135
+ snapshot.status = workerResult.status || (ok ? "completed" : "failed");
136
+ snapshot.provider_resolved =
137
+ workerResult.providerResolved || workerResult.provider_resolved || null;
136
138
  snapshot.transport = workerResult.transport || snapshot.transport;
137
- snapshot.output = workerResult.output || '';
138
- snapshot.stderr = workerResult.stderr || '';
139
- snapshot.error = workerResult.error || '';
140
- snapshot.thread_id = workerResult.threadId || workerResult.thread_id || null;
141
- snapshot.session_key = workerResult.sessionKey || workerResult.session_key || null;
142
- snapshot.conversation_open = workerResult.conversationOpen ?? workerResult.conversation_open ?? false;
139
+ snapshot.output = workerResult.output || "";
140
+ snapshot.stderr = workerResult.stderr || "";
141
+ snapshot.error = workerResult.error || "";
142
+ snapshot.thread_id =
143
+ workerResult.threadId || workerResult.thread_id || null;
144
+ snapshot.session_key =
145
+ workerResult.sessionKey || workerResult.session_key || null;
146
+ snapshot.conversation_open =
147
+ workerResult.conversationOpen ?? workerResult.conversation_open ?? false;
143
148
  snapshot.started_at = snapshot.started_at || timestamp;
144
149
  snapshot.updated_at = timestamp;
145
- if (snapshot.status === 'completed' || snapshot.status === 'failed') {
150
+ if (snapshot.status === "completed" || snapshot.status === "failed") {
146
151
  snapshot.completed_at = timestamp;
147
152
  }
148
153
 
@@ -155,7 +160,7 @@ export class DelegatorService {
155
160
  if (snapshot) {
156
161
  const timestamp = this.now().toISOString();
157
162
  snapshot.ok = false;
158
- snapshot.status = 'failed';
163
+ snapshot.status = "failed";
159
164
  snapshot.error = error;
160
165
  snapshot.updated_at = timestamp;
161
166
  snapshot.completed_at = timestamp;
@@ -169,19 +174,19 @@ export class DelegatorService {
169
174
  const timestamp = this.now().toISOString();
170
175
  return {
171
176
  ok: false,
172
- job_id: jobId || 'unknown',
173
- status: 'failed',
174
- mode: 'sync',
175
- provider_requested: 'auto',
177
+ job_id: jobId || "unknown",
178
+ status: "failed",
179
+ mode: "sync",
180
+ provider_requested: "auto",
176
181
  provider_resolved: null,
177
- agent_type: 'executor',
178
- transport: 'resident-pending',
182
+ agent_type: "executor",
183
+ transport: "resident-pending",
179
184
  created_at: timestamp,
180
185
  started_at: null,
181
186
  updated_at: timestamp,
182
187
  completed_at: timestamp,
183
- output: '',
184
- stderr: '',
188
+ output: "",
189
+ stderr: "",
185
190
  error,
186
191
  thread_id: null,
187
192
  session_key: null,
@@ -194,15 +199,19 @@ export class DelegatorService {
194
199
  async delegate(input = {}) {
195
200
  const normalized = this._normalizeInput(input);
196
201
 
197
- if (!normalized.prompt || typeof normalized.prompt !== 'string' || !normalized.prompt.trim()) {
198
- return this._errorSnapshot(null, 'prompt is required');
202
+ if (
203
+ !normalized.prompt ||
204
+ typeof normalized.prompt !== "string" ||
205
+ !normalized.prompt.trim()
206
+ ) {
207
+ return this._errorSnapshot(null, "prompt is required");
199
208
  }
200
209
 
201
210
  const snapshot = this.createJobSnapshot(normalized);
202
211
  this.recordJob(snapshot);
203
212
 
204
213
  if (!this.worker) {
205
- return this._failJob(snapshot.job_id, 'worker가 설정되지 않았습니다');
214
+ return this._failJob(snapshot.job_id, "worker가 설정되지 않았습니다");
206
215
  }
207
216
 
208
217
  const workerArgs = this._toWorkerArgs(normalized);
@@ -218,44 +227,53 @@ export class DelegatorService {
218
227
 
219
228
  return this._applyWorkerResult(snapshot.job_id, workerResult);
220
229
  } catch (err) {
221
- return this._failJob(snapshot.job_id, err instanceof Error ? err.message : String(err));
230
+ return this._failJob(
231
+ snapshot.job_id,
232
+ err instanceof Error ? err.message : String(err),
233
+ );
222
234
  }
223
235
  }
224
236
 
225
237
  async reply(input = {}) {
226
238
  const jobId = input.job_id || input.jobId;
227
239
  if (!jobId) {
228
- return this._errorSnapshot('unknown', 'job_id is required');
240
+ return this._errorSnapshot("unknown", "job_id is required");
229
241
  }
230
242
 
231
243
  const snapshot = this.jobs.get(jobId);
232
244
  if (!snapshot) {
233
- return this._errorSnapshot(jobId, 'job not found');
245
+ return this._errorSnapshot(jobId, "job not found");
234
246
  }
235
247
 
236
248
  if (!snapshot.conversation_open) {
237
- return this._failJob(jobId, 'conversation is not open');
249
+ return this._failJob(jobId, "conversation is not open");
238
250
  }
239
251
 
240
252
  if (!this.worker) {
241
- return this._failJob(jobId, 'worker가 설정되지 않았습니다');
253
+ return this._failJob(jobId, "worker가 설정되지 않았습니다");
242
254
  }
243
255
 
244
256
  const workerJobId = this._workerJobMap.get(jobId);
245
257
  if (!workerJobId) {
246
- return this._failJob(jobId, 'worker job 매핑을 찾을 수 없습니다');
258
+ return this._failJob(jobId, "worker job 매핑을 찾을 수 없습니다");
247
259
  }
248
260
 
249
261
  try {
250
- const workerResult = await this.worker.reply({
251
- job_id: workerJobId,
252
- reply: input.reply,
253
- done: input.done ?? false,
254
- }, null);
262
+ const workerResult = await this.worker.reply(
263
+ {
264
+ job_id: workerJobId,
265
+ reply: input.reply,
266
+ done: input.done ?? false,
267
+ },
268
+ null,
269
+ );
255
270
 
256
271
  return this._applyWorkerResult(jobId, workerResult);
257
272
  } catch (err) {
258
- return this._failJob(jobId, err instanceof Error ? err.message : String(err));
273
+ return this._failJob(
274
+ jobId,
275
+ err instanceof Error ? err.message : String(err),
276
+ );
259
277
  }
260
278
  }
261
279
 
@@ -267,20 +285,20 @@ export class DelegatorService {
267
285
  const timestamp = this.now().toISOString();
268
286
  return {
269
287
  ok: false,
270
- job_id: resolvedId || 'unknown-job',
271
- status: 'failed',
272
- mode: 'async',
273
- provider_requested: 'auto',
288
+ job_id: resolvedId || "unknown-job",
289
+ status: "failed",
290
+ mode: "async",
291
+ provider_requested: "auto",
274
292
  provider_resolved: null,
275
- agent_type: 'executor',
276
- transport: 'resident-pending',
293
+ agent_type: "executor",
294
+ transport: "resident-pending",
277
295
  created_at: timestamp,
278
296
  started_at: null,
279
297
  updated_at: timestamp,
280
298
  completed_at: null,
281
- output: '',
282
- stderr: '',
283
- error: 'job not found',
299
+ output: "",
300
+ stderr: "",
301
+ error: "job not found",
284
302
  thread_id: null,
285
303
  session_key: null,
286
304
  conversation_open: false,
@@ -288,11 +306,17 @@ export class DelegatorService {
288
306
  }
289
307
 
290
308
  // running/queued 상태이면 worker에서 최신 상태 갱신
291
- if (this.worker && (snapshot.status === 'running' || snapshot.status === 'queued')) {
309
+ if (
310
+ this.worker &&
311
+ (snapshot.status === "running" || snapshot.status === "queued")
312
+ ) {
292
313
  const workerJobId = this._workerJobMap.get(resolvedId);
293
314
  if (workerJobId) {
294
315
  try {
295
- const workerResult = await this.worker.getJobStatus(workerJobId, null);
316
+ const workerResult = await this.worker.getJobStatus(
317
+ workerJobId,
318
+ null,
319
+ );
296
320
  if (workerResult && workerResult.ok !== undefined) {
297
321
  return this._applyWorkerResult(resolvedId, workerResult);
298
322
  }
@@ -1,6 +1,6 @@
1
- import { readFileSync } from 'node:fs';
1
+ import { readFileSync } from "node:fs";
2
2
 
3
- import { DELEGATOR_SCHEMA_URL } from './contracts.mjs';
3
+ import { DELEGATOR_SCHEMA_URL } from "./contracts.mjs";
4
4
 
5
5
  let schemaBundleCache = null;
6
6
 
@@ -14,15 +14,15 @@ export function loadDelegatorSchemaBundle() {
14
14
  return schemaBundleCache;
15
15
  }
16
16
 
17
- schemaBundleCache = JSON.parse(readFileSync(DELEGATOR_SCHEMA_URL, 'utf8'));
17
+ schemaBundleCache = JSON.parse(readFileSync(DELEGATOR_SCHEMA_URL, "utf8"));
18
18
  return schemaBundleCache;
19
19
  }
20
20
 
21
21
  export function getDelegatorMcpToolDefinitions() {
22
22
  const bundle = loadDelegatorSchemaBundle();
23
23
  const defs = bundle.$defs || {};
24
- const tools = Array.isArray(bundle['x-triflux-mcp-tools'])
25
- ? bundle['x-triflux-mcp-tools']
24
+ const tools = Array.isArray(bundle["x-triflux-mcp-tools"])
25
+ ? bundle["x-triflux-mcp-tools"]
26
26
  : [];
27
27
 
28
28
  return tools.map((tool) => ({