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,88 @@
1
+ // ============================================================================
2
+ // 상수 / 경로
3
+ // ============================================================================
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+
7
+ export const VERSION = "2.0";
8
+
9
+ export const QOS_PATH = join(homedir(), ".omc", "state", "cli_qos_profile.json");
10
+ export const ACCOUNTS_CONFIG_PATH = join(homedir(), ".omc", "router", "accounts.json");
11
+ export const ACCOUNTS_STATE_PATH = join(homedir(), ".omc", "state", "cli_accounts_state.json");
12
+
13
+ // tfx-multi 상태 (v2.2 HUD 통합)
14
+ export const TEAM_STATE_PATH = join(homedir(), ".claude", "cache", "tfx-hub", "team-state.json");
15
+ export const CONTEXT_MONITOR_CACHE_PATH = join(homedir(), ".claude", "cache", "tfx-hub", "context-monitor.json");
16
+ export const CONTEXT_MONITOR_LEGACY_PATH = join(homedir(), ".omc", "state", "context-monitor.json");
17
+ export const CONTEXT_MONITOR_LOG_DIR = join(homedir(), ".omc", "logs");
18
+
19
+ // 원격 프로브 캐시 (tfx-remote-spawn)
20
+ export const REMOTE_ENV_CACHE_DIR = join(homedir(), ".claude", "cache", "tfx-hub", "remote-env");
21
+ export const REMOTE_ENV_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24시간
22
+
23
+ // Claude OAuth Usage API (api.anthropic.com/api/oauth/usage)
24
+ export const CLAUDE_CREDENTIALS_PATH = join(homedir(), ".claude", ".credentials.json");
25
+ export const CLAUDE_USAGE_CACHE_PATH = join(homedir(), ".claude", "cache", "claude-usage-cache.json");
26
+ export const OMC_PLUGIN_USAGE_CACHE_PATH = join(homedir(), ".claude", "plugins", "oh-my-claudecode", ".usage-cache.json");
27
+ export const CLAUDE_USAGE_STALE_MS_SOLO = 5 * 60 * 1000; // OMC 없을 때: 5분 캐시
28
+ export const CLAUDE_USAGE_STALE_MS_WITH_OMC = 15 * 60 * 1000; // OMC 있을 때: 15분 (OMC가 30초마다 갱신)
29
+ export const CLAUDE_USAGE_429_BACKOFF_MS = 10 * 60 * 1000; // 429 에러 시 10분 backoff
30
+ export const GEMINI_429_BASE_DELAY_MS = 2000;
31
+ export const GEMINI_429_MAX_RETRIES = 3;
32
+ export const GEMINI_429_COOLDOWN_MS = 30000;
33
+ export const CLAUDE_USAGE_ERROR_BACKOFF_MS = 3 * 60 * 1000; // 기타 에러 시 3분 backoff
34
+ export const CLAUDE_API_TIMEOUT_MS = 10_000;
35
+ export const FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
36
+ export const SEVEN_DAY_MS = 7 * 24 * 60 * 60 * 1000;
37
+ export const ONE_DAY_MS = 24 * 60 * 60 * 1000;
38
+ export const DEFAULT_OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
39
+
40
+ export const CODEX_AUTH_PATH = join(homedir(), ".codex", "auth.json");
41
+ export const CODEX_QUOTA_CACHE_PATH = join(homedir(), ".claude", "cache", "codex-rate-limits-cache.json");
42
+ export const CODEX_QUOTA_STALE_MS = 15 * 1000; // 15초
43
+ export const CODEX_MIN_BUCKETS = 2;
44
+
45
+ // Gemini 쿼터 API 관련
46
+ export const GEMINI_OAUTH_PATH = join(homedir(), ".gemini", "oauth_creds.json");
47
+ export const GEMINI_QUOTA_CACHE_PATH = join(homedir(), ".claude", "cache", "gemini-quota-cache.json");
48
+ export const GEMINI_PROJECT_CACHE_PATH = join(homedir(), ".claude", "cache", "gemini-project-id.json");
49
+ export const GEMINI_SESSION_CACHE_PATH = join(homedir(), ".claude", "cache", "gemini-session-cache.json");
50
+ export const GEMINI_RPM_TRACKER_PATH = join(homedir(), ".claude", "cache", "gemini-rpm-tracker.json");
51
+ export const SV_ACCUMULATOR_PATH = join(homedir(), ".claude", "cache", "sv-accumulator.json");
52
+ // 이전 .omc/ 경로 fallback (기존 환경 호환)
53
+ export const LEGACY_GEMINI_QUOTA_CACHE = join(homedir(), ".omc", "state", "gemini_quota_cache.json");
54
+ export const LEGACY_GEMINI_PROJECT_CACHE = join(homedir(), ".omc", "state", "gemini_project_id.json");
55
+ export const LEGACY_GEMINI_SESSION_CACHE = join(homedir(), ".omc", "state", "gemini_session_tokens_cache.json");
56
+ export const LEGACY_GEMINI_RPM_TRACKER = join(homedir(), ".omc", "state", "gemini_rpm_tracker.json");
57
+ export const LEGACY_SV_ACCUMULATOR = join(homedir(), ".omc", "state", "sv-accumulator.json");
58
+
59
+ export const GEMINI_RPM_WINDOW_MS = 60 * 1000; // 60초 슬라이딩 윈도우
60
+ export const GEMINI_QUOTA_STALE_MS = 5 * 60 * 1000; // 5분
61
+ export const GEMINI_SESSION_STALE_MS = 15 * 1000; // 15초
62
+ export const GEMINI_API_TIMEOUT_MS = 3000; // 3초
63
+
64
+ export const ACCOUNT_LABEL_WIDTH = 10;
65
+ export const PROVIDER_PREFIX_WIDTH = 2;
66
+ export const PERCENT_CELL_WIDTH = 3;
67
+ export const TIME_CELL_INNER_WIDTH = 6;
68
+ export const SV_CELL_WIDTH = 5;
69
+
70
+ export const CLAUDE_REFRESH_FLAG = "--refresh-claude-usage";
71
+ export const CODEX_REFRESH_FLAG = "--refresh-codex-rate-limits";
72
+ export const GEMINI_REFRESH_FLAG = "--refresh-gemini-quota";
73
+ export const GEMINI_SESSION_REFRESH_FLAG = "--refresh-gemini-session";
74
+
75
+ // 모바일/Termux 컴팩트 모드 감지
76
+ export const HUD_CONFIG_PATH = join(homedir(), ".omc", "config", "hud.json");
77
+ export const COMPACT_COLS_THRESHOLD = 80;
78
+ export const MINIMAL_COLS_THRESHOLD = 60;
79
+
80
+ // rows 임계값 상수 (selectTier 에서 tier 결정에 사용)
81
+ export const ROWS_BUDGET_FULL = 40;
82
+ export const ROWS_BUDGET_LARGE = 35;
83
+ export const ROWS_BUDGET_MEDIUM = 28;
84
+ export const ROWS_BUDGET_SMALL = 22;
85
+
86
+ // Gemini Pro 풀 공유 그룹: 같은 remainingFraction을 공유하는 모델 ID들
87
+ export const GEMINI_PRO_POOL = new Set(["gemini-2.5-pro", "gemini-3-pro-preview", "gemini-3.1-pro-preview"]);
88
+ export const GEMINI_FLASH_POOL = new Set(["gemini-2.5-flash", "gemini-3-flash-preview"]);
@@ -0,0 +1,403 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { homedir } from "node:os";
5
+
6
+ import {
7
+ CONTEXT_MONITOR_CACHE_PATH,
8
+ CONTEXT_MONITOR_LEGACY_PATH,
9
+ CONTEXT_MONITOR_LOG_DIR,
10
+ } from "./constants.mjs";
11
+ import { clampPercent, formatTokenCount, readJsonMigrate } from "./utils.mjs";
12
+
13
+ const DEFAULT_CONTEXT_LIMIT = 200_000;
14
+ const MAX_CAPTURE_BYTES = 256 * 1024;
15
+ const MAX_TOP_KEYS = 20;
16
+
17
+ const WARNING_LEVELS = Object.freeze({
18
+ ok: { min: 0, message: "" },
19
+ info: { min: 60, message: "컨텍스트 절반 이상 사용" },
20
+ warn: { min: 80, message: "압축 권장" },
21
+ critical: { min: 90, message: "에이전트 분할 또는 세션 교체 권장" },
22
+ });
23
+
24
+ // Unlike clampPercent (rounds), this preserves decimals for precise threshold comparison.
25
+ function clampThresholdPercent(value) {
26
+ const numeric = Number(value);
27
+ if (!Number.isFinite(numeric)) return 0;
28
+ return Math.max(0, Math.min(100, numeric));
29
+ }
30
+
31
+ function safeWriteJson(filePath, data) {
32
+ try {
33
+ mkdirSync(dirname(filePath), { recursive: true });
34
+ writeFileSync(filePath, JSON.stringify(data, null, 2), { mode: 0o600 });
35
+ } catch {
36
+ // noop
37
+ }
38
+ }
39
+
40
+ function normalizeText(input) {
41
+ if (typeof input === "string") return input;
42
+ if (input == null) return "";
43
+ try {
44
+ return JSON.stringify(input);
45
+ } catch {
46
+ return String(input);
47
+ }
48
+ }
49
+
50
+ function safeJsonParse(raw) {
51
+ if (typeof raw !== "string" || !raw.trim()) return null;
52
+ try {
53
+ return JSON.parse(raw);
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function toTokenEstimate(bytesOrText) {
60
+ if (typeof bytesOrText === "number" && Number.isFinite(bytesOrText)) {
61
+ if (bytesOrText <= 0) return 0;
62
+ return Math.max(1, Math.ceil(bytesOrText / 4));
63
+ }
64
+ const text = normalizeText(bytesOrText);
65
+ const bytes = Buffer.byteLength(text, "utf8");
66
+ if (bytes <= 0) return 0;
67
+ return Math.max(1, Math.ceil(bytes / 4));
68
+ }
69
+
70
+ function normalizeUsage(usage) {
71
+ if (!usage || typeof usage !== "object") return null;
72
+ const input = Number(usage.input_tokens ?? usage.inputTokens ?? 0);
73
+ const output = Number(usage.output_tokens ?? usage.outputTokens ?? 0);
74
+ const cacheCreation = Number(
75
+ usage.cache_creation_input_tokens
76
+ ?? usage.cacheCreationInputTokens
77
+ ?? usage.cache_creation_tokens
78
+ ?? 0,
79
+ );
80
+ const cacheRead = Number(
81
+ usage.cache_read_input_tokens
82
+ ?? usage.cacheReadInputTokens
83
+ ?? usage.cache_read_tokens
84
+ ?? 0,
85
+ );
86
+ const totalCandidate = Number(usage.total_tokens ?? usage.totalTokens ?? Number.NaN);
87
+ const total = Number.isFinite(totalCandidate) && totalCandidate > 0
88
+ ? totalCandidate
89
+ : input + output + cacheCreation + cacheRead;
90
+ if (!Number.isFinite(total) || total <= 0) return null;
91
+ return {
92
+ input: Math.max(0, Math.round(input)),
93
+ output: Math.max(0, Math.round(output)),
94
+ cacheCreation: Math.max(0, Math.round(cacheCreation)),
95
+ cacheRead: Math.max(0, Math.round(cacheRead)),
96
+ total: Math.max(0, Math.round(total)),
97
+ };
98
+ }
99
+
100
+ function extractUsage(payload) {
101
+ if (!payload || typeof payload !== "object") return null;
102
+
103
+ const queue = [payload];
104
+ const seen = new Set();
105
+
106
+ while (queue.length > 0) {
107
+ const current = queue.shift();
108
+ if (!current || typeof current !== "object") continue;
109
+ if (seen.has(current)) continue;
110
+ seen.add(current);
111
+
112
+ const directUsage = normalizeUsage(current.usage);
113
+ if (directUsage) return directUsage;
114
+
115
+ if (Array.isArray(current.content)) {
116
+ for (const item of current.content) queue.push(item);
117
+ }
118
+
119
+ for (const key of ["result", "payload", "response", "message", "data"]) {
120
+ if (current[key] && typeof current[key] === "object") {
121
+ queue.push(current[key]);
122
+ }
123
+ }
124
+ }
125
+ return null;
126
+ }
127
+
128
+ function bumpCounter(target, key, tokens) {
129
+ if (!key) return;
130
+ const prev = target[key] || 0;
131
+ target[key] = prev + tokens;
132
+ }
133
+
134
+ function pushTopKeys(inputMap, maxKeys = MAX_TOP_KEYS) {
135
+ const entries = Object.entries(inputMap || {});
136
+ entries.sort((a, b) => b[1] - a[1]);
137
+ return Object.fromEntries(entries.slice(0, maxKeys));
138
+ }
139
+
140
+ function extractFileKeys(args) {
141
+ if (!args || typeof args !== "object") return [];
142
+ const out = [];
143
+ const add = (value) => {
144
+ if (typeof value !== "string" || !value.trim()) return;
145
+ out.push(value.trim());
146
+ };
147
+ add(args.path);
148
+ add(args.file);
149
+ add(args.filename);
150
+ add(args.relative_path);
151
+ add(args.requestFilePath);
152
+ add(args.responseFilePath);
153
+ if (Array.isArray(args.paths)) {
154
+ for (const p of args.paths) add(p);
155
+ }
156
+ return Array.from(new Set(out)).slice(0, 5);
157
+ }
158
+
159
+ function detectSkillHints(payloadText) {
160
+ if (!payloadText) return [];
161
+ const matches = payloadText.match(/\$[a-z0-9_-]+/gi) || [];
162
+ return Array.from(new Set(matches.map((m) => m.replace(/^\$/, "")))).slice(0, 5);
163
+ }
164
+
165
+ export function estimateTokens(input) {
166
+ return toTokenEstimate(input);
167
+ }
168
+
169
+ export function parseUsageFromPayload(payload) {
170
+ return extractUsage(payload);
171
+ }
172
+
173
+ export function classifyContextThreshold(percent) {
174
+ const p = clampThresholdPercent(percent);
175
+ if (p >= WARNING_LEVELS.critical.min) return { level: "critical", message: WARNING_LEVELS.critical.message };
176
+ if (p >= WARNING_LEVELS.warn.min) return { level: "warn", message: WARNING_LEVELS.warn.message };
177
+ if (p >= WARNING_LEVELS.info.min) return { level: "info", message: WARNING_LEVELS.info.message };
178
+ return { level: "ok", message: "" };
179
+ }
180
+
181
+ export function formatContextUsage(usedTokens, limitTokens, percent = null) {
182
+ const used = Math.max(0, Math.round(Number(usedTokens) || 0));
183
+ const limit = Math.max(1, Math.round(Number(limitTokens) || DEFAULT_CONTEXT_LIMIT));
184
+ const pct = percent == null ? clampPercent((used / limit) * 100) : clampPercent(percent);
185
+ return `${formatTokenCount(used)}/${formatTokenCount(limit)} (${pct}%)`;
186
+ }
187
+
188
+ export function readContextMonitorSnapshot() {
189
+ return readJsonMigrate(CONTEXT_MONITOR_CACHE_PATH, CONTEXT_MONITOR_LEGACY_PATH, null);
190
+ }
191
+
192
+ function getStdinContextUsage(stdin) {
193
+ const limitTokens = Number(stdin?.context_window?.context_window_size || 0);
194
+ const nativePercent = Number(stdin?.context_window?.used_percentage);
195
+ const usage = stdin?.context_window?.current_usage || {};
196
+ const explicitUsed = Number(usage.total_tokens || 0);
197
+ const calculatedUsed = Number(usage.input_tokens || 0)
198
+ + Number(usage.cache_creation_input_tokens || 0)
199
+ + Number(usage.cache_read_input_tokens || 0);
200
+ const usedTokens = explicitUsed > 0 ? explicitUsed : calculatedUsed;
201
+
202
+ if (limitTokens > 0 && usedTokens > 0) {
203
+ return {
204
+ usedTokens: Math.round(usedTokens),
205
+ limitTokens: Math.round(limitTokens),
206
+ percent: clampPercent((usedTokens / limitTokens) * 100),
207
+ source: "stdin.tokens",
208
+ };
209
+ }
210
+
211
+ if (limitTokens > 0 && Number.isFinite(nativePercent)) {
212
+ const percent = clampPercent(nativePercent);
213
+ return {
214
+ usedTokens: Math.round((limitTokens * percent) / 100),
215
+ limitTokens: Math.round(limitTokens),
216
+ percent,
217
+ source: "stdin.percent",
218
+ };
219
+ }
220
+ return null;
221
+ }
222
+
223
+ export function buildContextUsageView(stdin, snapshot = null) {
224
+ const stdinUsage = getStdinContextUsage(stdin);
225
+ const monitor = snapshot || readContextMonitorSnapshot();
226
+ const fallbackLimit = Number(monitor?.limitTokens || DEFAULT_CONTEXT_LIMIT);
227
+
228
+ const usedTokens = stdinUsage?.usedTokens
229
+ ?? Number(monitor?.usedTokens || 0);
230
+ const limitTokens = stdinUsage?.limitTokens
231
+ ?? Math.max(1, fallbackLimit);
232
+ const percent = stdinUsage?.percent
233
+ ?? (limitTokens > 0 ? clampPercent((usedTokens / limitTokens) * 100) : 0);
234
+
235
+ const warning = classifyContextThreshold(percent);
236
+ return {
237
+ usedTokens,
238
+ limitTokens,
239
+ percent,
240
+ display: formatContextUsage(usedTokens, limitTokens, percent),
241
+ warningLevel: warning.level,
242
+ warningMessage: warning.message,
243
+ warningTag: warning.level === "warn" ? "⚠ 압축 권장"
244
+ : warning.level === "critical" ? "‼ 분할 권장"
245
+ : warning.level === "info" ? "ℹ 절반 이상 사용"
246
+ : "",
247
+ source: stdinUsage?.source || (monitor ? "monitor" : "none"),
248
+ };
249
+ }
250
+
251
+ export function createContextMonitor(options = {}) {
252
+ const limitTokens = Number(options.limitTokens || DEFAULT_CONTEXT_LIMIT);
253
+ const cachePath = options.cachePath || CONTEXT_MONITOR_CACHE_PATH;
254
+ const logsDir = options.logsDir || CONTEXT_MONITOR_LOG_DIR;
255
+ const sessionId = options.sessionId || randomUUID().slice(0, 8);
256
+ const registerExitHooks = options.registerExitHooks !== false;
257
+
258
+ const state = {
259
+ sessionId,
260
+ startedAt: new Date().toISOString(),
261
+ updatedAt: null,
262
+ limitTokens,
263
+ usedTokens: 0,
264
+ requestTokens: 0,
265
+ responseTokens: 0,
266
+ exactUsageTokens: 0,
267
+ totalUpdates: 0,
268
+ maxPercent: 0,
269
+ warningLevel: "ok",
270
+ warningMessage: "",
271
+ bySkill: {},
272
+ byFile: {},
273
+ byTool: {},
274
+ };
275
+
276
+ const writeSnapshot = () => {
277
+ const percent = clampPercent((state.usedTokens / state.limitTokens) * 100);
278
+ const warning = classifyContextThreshold(percent);
279
+ state.maxPercent = Math.max(state.maxPercent, percent);
280
+ state.warningLevel = warning.level;
281
+ state.warningMessage = warning.message;
282
+ state.updatedAt = new Date().toISOString();
283
+ safeWriteJson(cachePath, {
284
+ ...state,
285
+ display: formatContextUsage(state.usedTokens, state.limitTokens, percent),
286
+ percent,
287
+ bySkill: pushTopKeys(state.bySkill),
288
+ byFile: pushTopKeys(state.byFile),
289
+ byTool: pushTopKeys(state.byTool),
290
+ });
291
+ return { percent, warning };
292
+ };
293
+
294
+ const writeReport = (reason = "shutdown") => {
295
+ const percent = clampPercent((state.usedTokens / state.limitTokens) * 100);
296
+ const warning = classifyContextThreshold(percent);
297
+ const ts = new Date().toISOString().replace(/[:.]/g, "-");
298
+ const reportPath = join(logsDir, `context-usage-${state.sessionId}-${ts}.json`);
299
+ safeWriteJson(reportPath, {
300
+ sessionId: state.sessionId,
301
+ reason,
302
+ startedAt: state.startedAt,
303
+ endedAt: new Date().toISOString(),
304
+ summary: {
305
+ usedTokens: state.usedTokens,
306
+ limitTokens: state.limitTokens,
307
+ percent,
308
+ warningLevel: warning.level,
309
+ warningMessage: warning.message,
310
+ requestTokens: state.requestTokens,
311
+ responseTokens: state.responseTokens,
312
+ exactUsageTokens: state.exactUsageTokens,
313
+ updates: state.totalUpdates,
314
+ },
315
+ breakdown: {
316
+ skills: pushTopKeys(state.bySkill),
317
+ files: pushTopKeys(state.byFile),
318
+ tools: pushTopKeys(state.byTool),
319
+ },
320
+ });
321
+ return reportPath;
322
+ };
323
+
324
+ const record = ({
325
+ requestBody = null,
326
+ requestBytes = 0,
327
+ responseBody = null,
328
+ responseBytes = 0,
329
+ toolName = "",
330
+ } = {}) => {
331
+ const started = process.hrtime.bigint();
332
+ const reqObj = typeof requestBody === "object" ? requestBody : safeJsonParse(String(requestBody || ""));
333
+ const resObj = typeof responseBody === "object" ? responseBody : safeJsonParse(String(responseBody || ""));
334
+
335
+ const usage = parseUsageFromPayload(resObj);
336
+ const requestTokens = requestBytes > 0 ? toTokenEstimate(requestBytes) : toTokenEstimate(requestBody);
337
+ const responseTokens = usage?.total ?? (responseBytes > 0 ? toTokenEstimate(responseBytes) : toTokenEstimate(responseBody));
338
+ const totalTokens = Math.max(0, requestTokens + responseTokens);
339
+
340
+ const method = reqObj?.method || reqObj?.params?.name || "";
341
+ const name = toolName || reqObj?.params?.name || reqObj?.tool || "";
342
+ const args = reqObj?.params?.arguments || reqObj?.arguments || reqObj?.params || {};
343
+ const payloadText = normalizeText(requestBody).slice(0, MAX_CAPTURE_BYTES);
344
+ const skills = detectSkillHints(payloadText);
345
+ const files = extractFileKeys(args);
346
+
347
+ if (name) bumpCounter(state.byTool, String(name), totalTokens);
348
+ if (method?.includes("tool")) {
349
+ bumpCounter(state.byTool, String(method), totalTokens);
350
+ }
351
+ for (const file of files) bumpCounter(state.byFile, file, totalTokens);
352
+ for (const skill of skills) bumpCounter(state.bySkill, skill, totalTokens);
353
+
354
+ state.requestTokens += requestTokens;
355
+ state.responseTokens += responseTokens;
356
+ state.exactUsageTokens += usage?.total || 0;
357
+ state.usedTokens += totalTokens;
358
+ state.totalUpdates += 1;
359
+
360
+ const { percent, warning } = writeSnapshot();
361
+ const overheadMs = Number(process.hrtime.bigint() - started) / 1_000_000;
362
+
363
+ return {
364
+ requestTokens,
365
+ responseTokens,
366
+ totalTokens,
367
+ usedTokens: state.usedTokens,
368
+ limitTokens: state.limitTokens,
369
+ percent,
370
+ warningLevel: warning.level,
371
+ warningMessage: warning.message,
372
+ display: formatContextUsage(state.usedTokens, state.limitTokens, percent),
373
+ overheadMs: Math.round(overheadMs * 1000) / 1000,
374
+ };
375
+ };
376
+
377
+ let reportWritten = false;
378
+ const flush = (reason = "shutdown") => {
379
+ if (reportWritten) return null;
380
+ reportWritten = true;
381
+ return writeReport(reason);
382
+ };
383
+
384
+ if (registerExitHooks) {
385
+ const flushOnExit = () => {
386
+ try { flush("process.exit"); } catch {}
387
+ };
388
+ process.once("exit", flushOnExit);
389
+ process.once("SIGINT", flushOnExit);
390
+ process.once("SIGTERM", flushOnExit);
391
+ }
392
+
393
+ return {
394
+ record,
395
+ flush,
396
+ snapshot: () => ({
397
+ ...state,
398
+ bySkill: pushTopKeys(state.bySkill),
399
+ byFile: pushTopKeys(state.byFile),
400
+ byTool: pushTopKeys(state.byTool),
401
+ }),
402
+ };
403
+ }