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,103 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * tmp-cleanup.mjs — triflux 임시 파일 자동 정리
4
+ * 7일 이상 된 파일을 삭제한다.
5
+ * SessionStart 훅 또는 독립 실행으로 사용.
6
+ */
7
+ import { existsSync, readdirSync, statSync, rmSync } from "node:fs";
8
+ import { join, resolve } from "node:path";
9
+ import { tmpdir } from "node:os";
10
+
11
+ const MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7일
12
+ const TRIFLUX_CLI_MAX_AGE_MS = 24 * 60 * 60 * 1000; // 1일
13
+
14
+ // tfx-psmux-check.json은 guard가 TTL을 직접 관리하므로 제외
15
+ const SKIP_FILES = new Set(["tfx-psmux-check.json"]);
16
+ const TOP_LEVEL_RULES = Object.freeze([
17
+ { prefix: "tfx-", maxAgeMs: MAX_AGE_MS },
18
+ { prefix: "triflux-cli-", maxAgeMs: TRIFLUX_CLI_MAX_AGE_MS },
19
+ ]);
20
+
21
+ function normalizeProtectedPath(target) {
22
+ const normalized = resolve(target);
23
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
24
+ }
25
+
26
+ function buildProtectedPathSet(protectPaths = []) {
27
+ const protectedPaths = new Set();
28
+ for (const target of protectPaths) {
29
+ if (!target) continue;
30
+ try {
31
+ protectedPaths.add(normalizeProtectedPath(target));
32
+ } catch {
33
+ // ignore invalid paths
34
+ }
35
+ }
36
+ return protectedPaths;
37
+ }
38
+
39
+ /**
40
+ * 7일 이상 된 임시 파일/디렉터리를 정리한다.
41
+ * triflux-cli-* 테스트 홈 디렉터리는 1일 이상 지난 경우 정리한다.
42
+ * @param {{ protectPaths?: string[] }} [options]
43
+ * @returns {number} 삭제된 항목 수
44
+ */
45
+ export async function cleanupTmpFiles({ protectPaths = [] } = {}) {
46
+ const now = Date.now();
47
+ let cleaned = 0;
48
+ const tmp = tmpdir();
49
+ const protectedPaths = buildProtectedPathSet(protectPaths);
50
+
51
+ // 1) tmpdir() 직하위의 관리 대상 항목 정리
52
+ let topEntries;
53
+ try { topEntries = readdirSync(tmp); } catch { topEntries = []; }
54
+
55
+ for (const entry of topEntries) {
56
+ const rule = TOP_LEVEL_RULES.find(({ prefix }) => entry.startsWith(prefix));
57
+ if (!rule) continue;
58
+ if (SKIP_FILES.has(entry)) continue;
59
+
60
+ const full = join(tmp, entry);
61
+ if (protectedPaths.has(normalizeProtectedPath(full))) continue;
62
+
63
+ try {
64
+ const stat = statSync(full);
65
+ if (now - stat.mtimeMs > rule.maxAgeMs) {
66
+ rmSync(full, { recursive: true, force: true });
67
+ cleaned++;
68
+ }
69
+ } catch { /* 권한 에러 등 무시 */ }
70
+ }
71
+
72
+ // 2) tfx-headless/ 내 오래된 결과 파일 정리 (디렉터리 자체는 유지)
73
+ const headlessDir = join(tmp, "tfx-headless");
74
+ if (existsSync(headlessDir)) {
75
+ let entries;
76
+ try { entries = readdirSync(headlessDir); } catch { entries = []; }
77
+
78
+ for (const entry of entries) {
79
+ if (SKIP_FILES.has(entry)) continue;
80
+ const full = join(headlessDir, entry);
81
+ try {
82
+ const stat = statSync(full);
83
+ if (now - stat.mtimeMs > MAX_AGE_MS) {
84
+ rmSync(full, { recursive: true, force: true });
85
+ cleaned++;
86
+ }
87
+ } catch { /* 권한 에러 등 무시 */ }
88
+ }
89
+ }
90
+
91
+ return cleaned;
92
+ }
93
+
94
+ // 독립 실행 시 결과를 stdout으로 출력 (SessionStart 훅 호환)
95
+ if (process.argv[1]) {
96
+ const { fileURLToPath } = await import("node:url");
97
+ if (fileURLToPath(import.meta.url) === process.argv[1]) {
98
+ const cleaned = await cleanupTmpFiles();
99
+ if (cleaned > 0) {
100
+ process.stdout.write(JSON.stringify({ message: `tfx-cleanup: ${cleaned} files removed` }));
101
+ }
102
+ }
103
+ }
@@ -0,0 +1,575 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cx-auto Token Savings Tracker
4
+ * 스냅샷 기반 Codex/Gemini 토큰 사용량 추적 + Claude 절약액 계산
5
+ *
6
+ * 사용법:
7
+ * node token-snapshot.mjs snapshot <label>
8
+ * node token-snapshot.mjs diff <pre> <post> [--agent <agent>] [--cli <cli>] [--id <id>]
9
+ * node token-snapshot.mjs report <session-id|all>
10
+ */
11
+
12
+ import { readFileSync, writeFileSync, existsSync, readdirSync, mkdirSync, statSync } from "node:fs";
13
+ import { join, dirname } from "node:path";
14
+ import { homedir } from "node:os";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ const HOME = homedir();
18
+ const STATE_DIR = join(HOME, ".omc", "state", "cx-auto-tokens");
19
+ const SNAPSHOTS_DIR = join(STATE_DIR, "snapshots");
20
+ const DIFFS_DIR = join(STATE_DIR, "diffs");
21
+ const REPORTS_DIR = join(STATE_DIR, "reports");
22
+
23
+ // ── 가격 모델 ($/MTok, 비캐시 기준, 보수적 추정) ──
24
+ const PRICING = {
25
+ claude_sonnet: { input: 3, output: 15 },
26
+ claude_opus: { input: 15, output: 75 },
27
+ codex: { input: 0, output: 0 },
28
+ gemini_flash: { input: 0.10, output: 0.40 },
29
+ };
30
+
31
+ // Claude 캐시 가격 ($/MTok) — 오케스트레이션 비용 정밀 계산용
32
+ const CLAUDE_CACHE_PRICING = {
33
+ claude_sonnet: { cache_write: 3.75, cache_read: 0.30 },
34
+ claude_opus: { cache_write: 18.75, cache_read: 1.50 },
35
+ };
36
+
37
+ // 에이전트 → Claude 대체 모델
38
+ const AGENT_CLAUDE_MAP = {
39
+ executor: "claude_sonnet",
40
+ debugger: "claude_sonnet",
41
+ "build-fixer": "claude_sonnet",
42
+ "code-reviewer": "claude_sonnet",
43
+ "security-reviewer": "claude_sonnet",
44
+ "quality-reviewer": "claude_sonnet",
45
+ designer: "claude_sonnet",
46
+ writer: "claude_sonnet",
47
+ scientist: "claude_sonnet",
48
+ "document-specialist": "claude_sonnet",
49
+ "deep-executor": "claude_opus",
50
+ architect: "claude_opus",
51
+ planner: "claude_opus",
52
+ critic: "claude_opus",
53
+ analyst: "claude_opus",
54
+ };
55
+
56
+ // CLI → 실제 비용 모델
57
+ const CLI_COST_MAP = {
58
+ codex: "codex",
59
+ gemini: "gemini_flash",
60
+ };
61
+
62
+ // ── 유틸리티 ──
63
+ function readJson(filePath, fallback = null) {
64
+ if (!existsSync(filePath)) return fallback;
65
+ try { return JSON.parse(readFileSync(filePath, "utf-8")); }
66
+ catch { return fallback; }
67
+ }
68
+
69
+ function writeJsonSafe(filePath, data) {
70
+ try {
71
+ mkdirSync(dirname(filePath), { recursive: true });
72
+ writeFileSync(filePath, JSON.stringify(data, null, 2));
73
+ } catch (e) { console.error(`[token-snapshot] 쓰기 실패: ${e.message}`); }
74
+ }
75
+
76
+ function formatTokenCount(n) {
77
+ if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
78
+ if (n >= 1_000) return `${Math.round(n / 1_000)}K`;
79
+ return String(n);
80
+ }
81
+
82
+ function formatCost(dollars) {
83
+ if (dollars < 0.01) return "$0.00";
84
+ return `$${dollars.toFixed(2)}`;
85
+ }
86
+
87
+ function calcCost(tokens, pricing) {
88
+ return (tokens.input * pricing.input + tokens.output * pricing.output) / 1_000_000;
89
+ }
90
+
91
+ // ── Codex 세션 스캔 ──
92
+ // ~/.codex/sessions/YYYY/MM/DD/*.jsonl 에서 파일별 토큰 합산
93
+ function scanCodexSessions() {
94
+ const sessions = {};
95
+ const baseDir = join(HOME, ".codex", "sessions");
96
+ if (!existsSync(baseDir)) return sessions;
97
+
98
+ const now = Date.now();
99
+ for (let d = 0; d < 30; d++) {
100
+ const date = new Date(now - d * 86_400_000);
101
+ const dayDir = join(
102
+ baseDir,
103
+ String(date.getFullYear()),
104
+ String(date.getMonth() + 1).padStart(2, "0"),
105
+ String(date.getDate()).padStart(2, "0"),
106
+ );
107
+ if (!existsSync(dayDir)) continue;
108
+
109
+ let files;
110
+ try { files = readdirSync(dayDir).filter(f => f.endsWith(".jsonl")); }
111
+ catch { continue; }
112
+
113
+ for (const file of files) {
114
+ const filepath = join(dayDir, file);
115
+ try {
116
+ const stat = statSync(filepath);
117
+ const content = readFileSync(filepath, "utf-8");
118
+ const lines = content.trim().split("\n").reverse();
119
+ for (const line of lines) {
120
+ try {
121
+ const evt = JSON.parse(line);
122
+ const t = evt?.payload?.info?.total_token_usage;
123
+ if (t) {
124
+ sessions[filepath] = {
125
+ input: t.input_tokens || t.input || 0,
126
+ output: t.output_tokens || t.output || 0,
127
+ total: t.total_tokens || t.total || ((t.input_tokens || t.input || 0) + (t.output_tokens || t.output || 0)),
128
+ timestamp: evt.timestamp || stat.mtimeMs,
129
+ };
130
+ break;
131
+ }
132
+ } catch { /* 라인 파싱 실패 */ }
133
+ }
134
+ // 토큰 이벤트 없는 파일도 기록 (존재 추적용)
135
+ if (!sessions[filepath]) {
136
+ sessions[filepath] = { input: 0, output: 0, total: 0, timestamp: stat.mtimeMs };
137
+ }
138
+ } catch { /* 파일 읽기 실패 */ }
139
+ }
140
+ }
141
+ return sessions;
142
+ }
143
+
144
+ // ── Gemini 세션 스캔 ──
145
+ // ~/.gemini/tmp/*/chats/*.json 에서 파일별 토큰 합산
146
+ function scanGeminiSessions() {
147
+ const sessions = {};
148
+ const tmpDir = join(HOME, ".gemini", "tmp");
149
+ if (!existsSync(tmpDir)) return sessions;
150
+
151
+ try {
152
+ const dirs = readdirSync(tmpDir);
153
+ for (const dir of dirs) {
154
+ const chatsDir = join(tmpDir, dir, "chats");
155
+ if (!existsSync(chatsDir)) continue;
156
+
157
+ let files;
158
+ try { files = readdirSync(chatsDir).filter(f => f.endsWith(".json")); }
159
+ catch { continue; }
160
+
161
+ for (const file of files) {
162
+ const filepath = join(chatsDir, file);
163
+ try {
164
+ const data = JSON.parse(readFileSync(filepath, "utf-8"));
165
+ let input = 0, output = 0, model = "unknown";
166
+ for (const msg of data.messages || []) {
167
+ if (msg.tokens) {
168
+ input += msg.tokens.input || 0;
169
+ output += msg.tokens.output || 0;
170
+ }
171
+ if (msg.model) model = msg.model;
172
+ }
173
+ sessions[filepath] = {
174
+ input, output, total: input + output,
175
+ model, lastUpdated: data.lastUpdated || null,
176
+ };
177
+ } catch { /* 무시 */ }
178
+ }
179
+ }
180
+ } catch { /* 무시 */ }
181
+ return sessions;
182
+ }
183
+
184
+ // ── Claude 세션 스캔 ──
185
+ // ~/.claude/projects/*/*.jsonl 에서 requestId별 마지막 이벤트의 usage 합산
186
+ function scanClaudeSessions() {
187
+ const sessions = {};
188
+ const projectsDir = join(HOME, ".claude", "projects");
189
+ if (!existsSync(projectsDir)) return sessions;
190
+
191
+ try {
192
+ const projects = readdirSync(projectsDir);
193
+ for (const proj of projects) {
194
+ const projDir = join(projectsDir, proj);
195
+ let stat;
196
+ try { stat = statSync(projDir); } catch { continue; }
197
+ if (!stat.isDirectory()) continue;
198
+
199
+ let files;
200
+ try { files = readdirSync(projDir).filter(f => f.endsWith(".jsonl")); }
201
+ catch { continue; }
202
+
203
+ for (const file of files) {
204
+ const filepath = join(projDir, file);
205
+ try {
206
+ const fileStat = statSync(filepath);
207
+ // 최근 7일 내 파일만 스캔 (성능)
208
+ if (Date.now() - fileStat.mtimeMs > 7 * 86_400_000) continue;
209
+
210
+ const content = readFileSync(filepath, "utf-8");
211
+ const lines = content.trim().split("\n");
212
+
213
+ // requestId별 마지막 이벤트의 usage만 수집 (중복 방지)
214
+ const reqUsage = {};
215
+ let model = "unknown";
216
+
217
+ for (const line of lines) {
218
+ try {
219
+ const evt = JSON.parse(line);
220
+ if (evt.type !== "assistant") continue;
221
+ const msg = evt.message;
222
+ if (!msg?.usage) continue;
223
+
224
+ const reqId = evt.requestId || msg.id;
225
+ if (!reqId) continue;
226
+ if (msg.model) model = msg.model;
227
+
228
+ reqUsage[reqId] = {
229
+ input: msg.usage.input_tokens || 0,
230
+ output: msg.usage.output_tokens || 0,
231
+ cache_creation: msg.usage.cache_creation_input_tokens || 0,
232
+ cache_read: msg.usage.cache_read_input_tokens || 0,
233
+ };
234
+ } catch { /* 라인 파싱 실패 */ }
235
+ }
236
+
237
+ // requestId별 usage 합산
238
+ let input = 0, output = 0, cache_creation = 0, cache_read = 0;
239
+ for (const u of Object.values(reqUsage)) {
240
+ input += u.input;
241
+ output += u.output;
242
+ cache_creation += u.cache_creation;
243
+ cache_read += u.cache_read;
244
+ }
245
+
246
+ const total = input + output + cache_creation + cache_read;
247
+ if (total > 0) {
248
+ sessions[filepath] = {
249
+ input, output, cache_creation, cache_read,
250
+ total, model,
251
+ timestamp: fileStat.mtimeMs,
252
+ requests: Object.keys(reqUsage).length,
253
+ };
254
+ }
255
+ } catch { /* 파일 읽기 실패 */ }
256
+ }
257
+ }
258
+ } catch { /* 무시 */ }
259
+ return sessions;
260
+ }
261
+
262
+ // ── 스냅샷 캡처 ──
263
+ function takeSnapshot(label) {
264
+ const codex = scanCodexSessions();
265
+ const gemini = scanGeminiSessions();
266
+ const claude = scanClaudeSessions();
267
+ const snapshot = {
268
+ label,
269
+ timestamp: new Date().toISOString(),
270
+ codex,
271
+ gemini,
272
+ claude,
273
+ summary: {
274
+ codex_files: Object.keys(codex).length,
275
+ gemini_files: Object.keys(gemini).length,
276
+ claude_files: Object.keys(claude).length,
277
+ codex_total: Object.values(codex).reduce((s, v) => s + v.total, 0),
278
+ gemini_total: Object.values(gemini).reduce((s, v) => s + v.total, 0),
279
+ claude_total: Object.values(claude).reduce((s, v) => s + v.total, 0),
280
+ },
281
+ };
282
+
283
+ const outPath = join(SNAPSHOTS_DIR, `${label}.json`);
284
+ writeJsonSafe(outPath, snapshot);
285
+ console.log(`[snapshot] ${label} 저장 완료`);
286
+ console.log(` Codex: ${snapshot.summary.codex_files}파일, ${formatTokenCount(snapshot.summary.codex_total)} tokens`);
287
+ console.log(` Gemini: ${snapshot.summary.gemini_files}파일, ${formatTokenCount(snapshot.summary.gemini_total)} tokens`);
288
+ console.log(` Claude: ${snapshot.summary.claude_files}파일, ${formatTokenCount(snapshot.summary.claude_total)} tokens`);
289
+ return snapshot;
290
+ }
291
+
292
+ // ── 두 스냅샷 간 Diff ──
293
+ function computeDiff(preLabel, postLabel, options = {}) {
294
+ const pre = readJson(join(SNAPSHOTS_DIR, `${preLabel}.json`));
295
+ const post = readJson(join(SNAPSHOTS_DIR, `${postLabel}.json`));
296
+ if (!pre || !post) {
297
+ console.error(`[diff] 스냅샷 없음: ${!pre ? preLabel : postLabel}`);
298
+ process.exit(1);
299
+ }
300
+
301
+ const delta = { codex: {}, gemini: {}, claude: {}, total: { input: 0, output: 0, total: 0 } };
302
+
303
+ // Claude diff — 오케스트레이션 오버헤드 측정
304
+ const preClaude = pre.claude || {};
305
+ const postClaude = post.claude || {};
306
+ const claudeOverhead = { input: 0, output: 0, cache_creation: 0, cache_read: 0, total: 0 };
307
+ for (const [fp, postData] of Object.entries(postClaude)) {
308
+ const preData = preClaude[fp];
309
+ if (!preData) {
310
+ if (postData.total > 0) {
311
+ delta.claude[fp] = { ...postData, type: "new" };
312
+ claudeOverhead.input += postData.input || 0;
313
+ claudeOverhead.output += postData.output || 0;
314
+ claudeOverhead.cache_creation += postData.cache_creation || 0;
315
+ claudeOverhead.cache_read += postData.cache_read || 0;
316
+ claudeOverhead.total += postData.total;
317
+ }
318
+ } else if (postData.total > preData.total) {
319
+ const d = {
320
+ input: (postData.input || 0) - (preData.input || 0),
321
+ output: (postData.output || 0) - (preData.output || 0),
322
+ cache_creation: (postData.cache_creation || 0) - (preData.cache_creation || 0),
323
+ cache_read: (postData.cache_read || 0) - (preData.cache_read || 0),
324
+ total: postData.total - preData.total,
325
+ type: "increased",
326
+ };
327
+ delta.claude[fp] = d;
328
+ claudeOverhead.input += d.input;
329
+ claudeOverhead.output += d.output;
330
+ claudeOverhead.cache_creation += d.cache_creation;
331
+ claudeOverhead.cache_read += d.cache_read;
332
+ claudeOverhead.total += d.total;
333
+ }
334
+ }
335
+ delta.claudeOverhead = claudeOverhead;
336
+
337
+ // Codex diff — 새 파일 또는 증가분 감지
338
+ for (const [fp, postData] of Object.entries(post.codex)) {
339
+ const preData = pre.codex[fp];
340
+ if (!preData) {
341
+ if (postData.total > 0) {
342
+ delta.codex[fp] = { ...postData, type: "new" };
343
+ delta.total.input += postData.input;
344
+ delta.total.output += postData.output;
345
+ delta.total.total += postData.total;
346
+ }
347
+ } else if (postData.total > preData.total) {
348
+ const d = {
349
+ input: postData.input - preData.input,
350
+ output: postData.output - preData.output,
351
+ total: postData.total - preData.total,
352
+ type: "increased",
353
+ };
354
+ delta.codex[fp] = d;
355
+ delta.total.input += d.input;
356
+ delta.total.output += d.output;
357
+ delta.total.total += d.total;
358
+ }
359
+ }
360
+
361
+ // Gemini diff
362
+ for (const [fp, postData] of Object.entries(post.gemini)) {
363
+ const preData = pre.gemini[fp];
364
+ if (!preData) {
365
+ if (postData.total > 0) {
366
+ delta.gemini[fp] = { ...postData, type: "new" };
367
+ delta.total.input += postData.input;
368
+ delta.total.output += postData.output;
369
+ delta.total.total += postData.total;
370
+ }
371
+ } else if (postData.total > preData.total) {
372
+ const d = {
373
+ input: postData.input - preData.input,
374
+ output: postData.output - preData.output,
375
+ total: postData.total - preData.total,
376
+ model: postData.model,
377
+ type: "increased",
378
+ };
379
+ delta.gemini[fp] = d;
380
+ delta.total.input += d.input;
381
+ delta.total.output += d.output;
382
+ delta.total.total += d.total;
383
+ }
384
+ }
385
+
386
+ // 절약 계산 (Claude 오버헤드 반영)
387
+ const agent = options.agent || "executor";
388
+ const cli = options.cli || "codex";
389
+ const savings = estimateSavings(delta.total, agent, cli, claudeOverhead);
390
+
391
+ const result = {
392
+ preLabel, postLabel, agent, cli,
393
+ timestamp: new Date().toISOString(),
394
+ delta,
395
+ savings,
396
+ };
397
+
398
+ const diffId = options.id || `${preLabel}__${postLabel}`;
399
+ writeJsonSafe(join(DIFFS_DIR, `${diffId}.json`), result);
400
+
401
+ // 누적 절약액 업데이트 (HUD ts: 표시용)
402
+ const accPath = join(STATE_DIR, "savings-total.json");
403
+ const acc = readJson(accPath, { totalSaved: 0, totalClaudeCost: 0, totalActualCost: 0, diffCount: 0 });
404
+ acc.totalSaved += savings.saved;
405
+ acc.totalClaudeCost += savings.claudeCost;
406
+ acc.totalActualCost += savings.actualCost;
407
+ acc.diffCount += 1;
408
+ acc.lastUpdated = new Date().toISOString();
409
+ writeJsonSafe(accPath, acc);
410
+
411
+ console.log(`[diff] ${preLabel} → ${postLabel}`);
412
+ console.log(` Agent: ${agent} (${cli})`);
413
+ console.log(` 외부 CLI 토큰: ${formatTokenCount(delta.total.input)} input, ${formatTokenCount(delta.total.output)} output`);
414
+ console.log(` Claude 오케스트레이션: ${formatTokenCount(claudeOverhead.total)} tokens (오버헤드 ${formatCost(savings.overheadCost)})`);
415
+ console.log(` Claude-only 비용(추정): ${formatCost(savings.claudeCost)}`);
416
+ console.log(` 실제 비용: ${formatCost(savings.actualCost)} (외부 CLI ${formatCost(savings.cliCost)} + 오케스트레이션 ${formatCost(savings.overheadCost)})`);
417
+ console.log(` 순절약: ${formatCost(savings.saved)}`);
418
+ return result;
419
+ }
420
+
421
+ // ── 절약액 계산 ──
422
+ // claudeOverhead: { input, output, cache_creation, cache_read } — 오케스트레이션에 쓴 Claude 토큰
423
+ function estimateSavings(tokens, agent, cli, claudeOverhead = null) {
424
+ const claudeModel = AGENT_CLAUDE_MAP[agent] || "claude_sonnet";
425
+ const claudePricing = PRICING[claudeModel];
426
+ // Claude가 직접 했다면의 추정 비용
427
+ const claudeCost = calcCost(tokens, claudePricing);
428
+
429
+ const costModel = CLI_COST_MAP[cli] || "codex";
430
+ const actualPricing = PRICING[costModel];
431
+ // 외부 CLI 실비용
432
+ const cliCost = calcCost(tokens, actualPricing);
433
+
434
+ // Claude 오케스트레이션 오버헤드 비용 계산
435
+ let overheadCost = 0;
436
+ if (claudeOverhead && claudeOverhead.total > 0) {
437
+ // 일반 input/output 비용
438
+ overheadCost += calcCost(
439
+ { input: claudeOverhead.input, output: claudeOverhead.output },
440
+ claudePricing,
441
+ );
442
+ // 캐시 비용 (cache_creation은 write 가격, cache_read는 read 가격)
443
+ const cachePricing = CLAUDE_CACHE_PRICING[claudeModel] || CLAUDE_CACHE_PRICING.claude_sonnet;
444
+ overheadCost += (claudeOverhead.cache_creation * cachePricing.cache_write) / 1_000_000;
445
+ overheadCost += (claudeOverhead.cache_read * cachePricing.cache_read) / 1_000_000;
446
+ }
447
+
448
+ // 실제 총비용 = 외부 CLI 비용 + Claude 오케스트레이션 비용
449
+ const actualCost = cliCost + overheadCost;
450
+
451
+ return {
452
+ claudeModel,
453
+ claudeCost,
454
+ actualModel: costModel,
455
+ cliCost,
456
+ overheadCost,
457
+ actualCost,
458
+ saved: claudeCost - actualCost,
459
+ tokens: { ...tokens },
460
+ orchestration: claudeOverhead ? { ...claudeOverhead } : null,
461
+ };
462
+ }
463
+
464
+ // ── 종합 보고서 ──
465
+ function generateReport(sessionId) {
466
+ if (!existsSync(DIFFS_DIR)) {
467
+ console.error("[report] diff 데이터 없음");
468
+ process.exit(1);
469
+ }
470
+
471
+ const files = readdirSync(DIFFS_DIR).filter(f => f.endsWith(".json"));
472
+ const diffs = [];
473
+ for (const file of files) {
474
+ const data = readJson(join(DIFFS_DIR, file));
475
+ if (!data) continue;
476
+ if (sessionId === "all" || file.includes(sessionId)) {
477
+ diffs.push(data);
478
+ }
479
+ }
480
+
481
+ if (diffs.length === 0) {
482
+ console.log(`[report] ${sessionId}에 해당하는 diff 없음`);
483
+ return null;
484
+ }
485
+
486
+ let totalClaudeCost = 0, totalActualCost = 0, totalSaved = 0, totalOverhead = 0;
487
+ const rows = diffs.map((d, i) => {
488
+ const s = d.savings;
489
+ totalClaudeCost += s.claudeCost;
490
+ totalActualCost += s.actualCost;
491
+ totalSaved += s.saved;
492
+ totalOverhead += s.overheadCost || 0;
493
+ const overhead = s.overheadCost ? formatCost(s.overheadCost) : "-";
494
+ return `| ${i + 1} | ${d.preLabel}→${d.postLabel} | ${d.agent} | ${d.cli} | ${formatTokenCount(s.tokens.input)} | ${formatTokenCount(s.tokens.output)} | ${formatCost(s.claudeCost)} | ${overhead} | ${formatCost(s.actualCost)} | ${formatCost(s.saved)} |`;
495
+ });
496
+
497
+ const report = [
498
+ "### Token Savings Report",
499
+ "",
500
+ "| # | 서브태스크 | Agent | CLI | Input | Output | Claude-only(추정) | 오케스트레이션 | 실제 비용 | 순절약 |",
501
+ "|---|----------|-------|-----|-------|--------|------------------|-------------|---------|--------|",
502
+ ...rows,
503
+ "",
504
+ `**순절약: ${formatCost(totalSaved)}** (Claude-only 추정 ${formatCost(totalClaudeCost)}, 실제 ${formatCost(totalActualCost)}, 오케스트레이션 ${formatCost(totalOverhead)})`,
505
+ ].join("\n");
506
+
507
+ console.log(report);
508
+
509
+ const reportData = {
510
+ sessionId,
511
+ timestamp: new Date().toISOString(),
512
+ diffs: diffs.map(d => ({
513
+ ...d.savings, agent: d.agent, cli: d.cli,
514
+ labels: `${d.preLabel}→${d.postLabel}`,
515
+ })),
516
+ totals: { claudeCost: totalClaudeCost, actualCost: totalActualCost, saved: totalSaved },
517
+ markdown: report,
518
+ };
519
+ writeJsonSafe(join(REPORTS_DIR, `${sessionId}.json`), reportData);
520
+ return reportData;
521
+ }
522
+
523
+ // ── Named exports (파이프라인 벤치마크 훅용) ──
524
+ export { takeSnapshot, computeDiff, estimateSavings, formatTokenCount, formatCost, DIFFS_DIR, STATE_DIR };
525
+
526
+ // ── CLI 핸들러 (직접 실행 시에만) ──
527
+ const __filename = fileURLToPath(import.meta.url);
528
+ const isDirectRun = process.argv[1] && join(dirname(process.argv[1])) === dirname(__filename)
529
+ && process.argv[1].endsWith("token-snapshot.mjs");
530
+
531
+ if (!isDirectRun) {
532
+ // imported as module — skip CLI
533
+ } else {
534
+
535
+ const [,, command, ...args] = process.argv;
536
+
537
+ switch (command) {
538
+ case "snapshot": {
539
+ const label = args[0];
540
+ if (!label) { console.error("사용법: token-snapshot.mjs snapshot <label>"); process.exit(1); }
541
+ takeSnapshot(label);
542
+ break;
543
+ }
544
+ case "diff": {
545
+ const [preLabel, postLabel, ...rest] = args;
546
+ if (!preLabel || !postLabel) {
547
+ console.error("사용법: token-snapshot.mjs diff <pre> <post> [--agent X] [--cli Y] [--id Z]");
548
+ process.exit(1);
549
+ }
550
+ const options = {};
551
+ for (let i = 0; i < rest.length; i++) {
552
+ if (rest[i] === "--agent" && rest[i + 1]) options.agent = rest[++i];
553
+ else if (rest[i] === "--cli" && rest[i + 1]) options.cli = rest[++i];
554
+ else if (rest[i] === "--id" && rest[i + 1]) options.id = rest[++i];
555
+ }
556
+ computeDiff(preLabel, postLabel, options);
557
+ break;
558
+ }
559
+ case "report": {
560
+ const sessionId = args[0] || "all";
561
+ generateReport(sessionId);
562
+ break;
563
+ }
564
+ default:
565
+ console.log(`cx-auto Token Savings Tracker
566
+
567
+ 사용법:
568
+ node token-snapshot.mjs snapshot <label> 스냅샷 캡처
569
+ node token-snapshot.mjs diff <pre> <post> 두 스냅샷 비교
570
+ [--agent <agent>] [--cli <cli>] [--id <id>]
571
+ node token-snapshot.mjs report <session-id> 종합 보고서 생성
572
+ (session-id 대신 "all"로 전체 보고서)`);
573
+ }
574
+
575
+ } // end isDirectRun guard
@@ -27,10 +27,9 @@ triggers:
27
27
  argument-hint: "<command|task> [args...]"
28
28
  ---
29
29
 
30
- # tfx-auto — 통합 CLI 오케스트레이터
30
+ # {{SKILL_NAME}} — 통합 CLI 오케스트레이터
31
31
 
32
- > **ARGUMENTS 처리**: 이 스킬이 `ARGUMENTS: <값>`과 함께 호출되면, 해당 값을 사용자 입력으로 취급하여
33
- > 워크플로우의 첫 단계 입력으로 사용한다. ARGUMENTS가 비어있거나 없으면 기존 절차대로 사용자에게 입력을 요청한다.
32
+ {{> base}}
34
33
 
35
34
 
36
35
  > **MANDATORY RULES**