triflux 10.4.0 → 10.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. package/.claude-plugin/marketplace.json +34 -0
  2. package/.claude-plugin/plugin.json +22 -0
  3. package/bin/tfx-doctor-tui.mjs +1 -1
  4. package/bin/tfx-doctor.mjs +6 -1
  5. package/bin/tfx-profile.mjs +1 -1
  6. package/bin/tfx-setup-tui.mjs +1 -1
  7. package/bin/tfx-setup.mjs +6 -1
  8. package/bin/triflux.mjs +2396 -1140
  9. package/config/mcp-registry.json +29 -0
  10. package/hooks/agent-route-guard.mjs +12 -8
  11. package/hooks/cross-review-tracker.mjs +21 -8
  12. package/hooks/error-context.mjs +19 -7
  13. package/hooks/hook-adaptive-collector.mjs +18 -16
  14. package/hooks/hook-manager.mjs +93 -32
  15. package/hooks/hook-orchestrator.mjs +108 -24
  16. package/hooks/hook-registry.json +267 -256
  17. package/hooks/keyword-rules.json +6 -10
  18. package/hooks/lib/resolve-root.mjs +1 -1
  19. package/hooks/mcp-config-watcher.mjs +6 -2
  20. package/hooks/pipeline-stop.mjs +3 -6
  21. package/hooks/safety-guard.mjs +99 -28
  22. package/hooks/session-start-fast.mjs +143 -0
  23. package/hooks/subagent-verifier.mjs +5 -4
  24. package/hub/account-broker.mjs +256 -60
  25. package/hub/adaptive-diagnostic.mjs +75 -48
  26. package/hub/adaptive-inject.mjs +96 -58
  27. package/hub/adaptive-memory.mjs +156 -42
  28. package/hub/adaptive.mjs +60 -31
  29. package/hub/assign-callbacks.mjs +163 -126
  30. package/hub/bridge.mjs +0 -1
  31. package/hub/cli-adapter-base.mjs +200 -48
  32. package/hub/codex-adapter.mjs +76 -96
  33. package/hub/codex-compat.mjs +3 -3
  34. package/hub/codex-preflight.mjs +63 -37
  35. package/hub/delegator/contracts.mjs +19 -23
  36. package/hub/delegator/index.mjs +14 -14
  37. package/hub/delegator/service.mjs +88 -64
  38. package/hub/delegator/tool-definitions.mjs +35 -35
  39. package/hub/fullcycle.mjs +33 -17
  40. package/hub/gemini-adapter.mjs +69 -94
  41. package/hub/hitl.mjs +202 -143
  42. package/hub/intent.mjs +161 -38
  43. package/hub/lib/cache-guard.mjs +43 -17
  44. package/hub/lib/mcp-response-cache.mjs +66 -32
  45. package/hub/lib/memory-store.mjs +285 -111
  46. package/hub/lib/path-utils.mjs +35 -37
  47. package/hub/lib/process-utils.mjs +106 -37
  48. package/hub/lib/spawn-trace.mjs +527 -0
  49. package/hub/lib/ssh-command.mjs +34 -4
  50. package/hub/lib/ssh-retry.mjs +5 -1
  51. package/hub/lib/uuidv7.mjs +4 -3
  52. package/hub/memory-doctor.mjs +266 -106
  53. package/hub/middleware/request-logger.mjs +61 -34
  54. package/hub/paths.mjs +9 -9
  55. package/hub/pipeline/gates/confidence.mjs +34 -15
  56. package/hub/pipeline/gates/consensus.mjs +27 -15
  57. package/hub/pipeline/gates/index.mjs +7 -3
  58. package/hub/pipeline/gates/selfcheck.mjs +57 -19
  59. package/hub/pipeline/index.mjs +77 -42
  60. package/hub/pipeline/state.mjs +10 -10
  61. package/hub/pipeline/transitions.mjs +40 -23
  62. package/hub/platform.mjs +57 -48
  63. package/hub/promote-penalties.mjs +25 -7
  64. package/hub/quality/deslop.mjs +70 -49
  65. package/hub/research.mjs +32 -25
  66. package/hub/router.mjs +924 -791
  67. package/hub/routing/complexity.mjs +132 -29
  68. package/hub/routing/index.mjs +17 -12
  69. package/hub/routing/q-learning.mjs +76 -28
  70. package/hub/server.mjs +4 -4
  71. package/hub/session-fingerprint.mjs +127 -61
  72. package/hub/state.mjs +84 -43
  73. package/hub/store-adapter.mjs +59 -26
  74. package/hub/store.mjs +356 -153
  75. package/hub/team/agent-map.json +22 -7
  76. package/hub/team/ansi.mjs +186 -122
  77. package/hub/team/backend.mjs +28 -10
  78. package/hub/team/cli/commands/attach.mjs +57 -37
  79. package/hub/team/cli/commands/control.mjs +29 -8
  80. package/hub/team/cli/commands/debug.mjs +95 -74
  81. package/hub/team/cli/commands/focus.mjs +80 -53
  82. package/hub/team/cli/commands/interrupt.mjs +18 -6
  83. package/hub/team/cli/commands/kill.mjs +16 -5
  84. package/hub/team/cli/commands/list.mjs +31 -24
  85. package/hub/team/cli/commands/send.mjs +19 -6
  86. package/hub/team/cli/commands/start/index.mjs +154 -31
  87. package/hub/team/cli/commands/start/parse-args.mjs +38 -11
  88. package/hub/team/cli/commands/start/start-headless.mjs +112 -36
  89. package/hub/team/cli/commands/start/start-in-process.mjs +50 -40
  90. package/hub/team/cli/commands/start/start-mux.mjs +122 -73
  91. package/hub/team/cli/commands/start/start-wt.mjs +86 -69
  92. package/hub/team/cli/commands/status.mjs +43 -14
  93. package/hub/team/cli/commands/stop.mjs +11 -4
  94. package/hub/team/cli/commands/task.mjs +8 -3
  95. package/hub/team/cli/commands/tasks.mjs +13 -13
  96. package/hub/team/cli/index.mjs +2 -2
  97. package/hub/team/cli/manifest.mjs +38 -8
  98. package/hub/team/cli/render.mjs +52 -30
  99. package/hub/team/cli/services/attach-fallback.mjs +74 -54
  100. package/hub/team/cli/services/hub-client.mjs +42 -14
  101. package/hub/team/cli/services/member-selector.mjs +37 -30
  102. package/hub/team/cli/services/native-control.mjs +143 -116
  103. package/hub/team/cli/services/runtime-mode.mjs +2 -1
  104. package/hub/team/cli/services/state-store.mjs +25 -8
  105. package/hub/team/cli/services/task-model.mjs +40 -30
  106. package/hub/team/conductor-mesh-bridge.mjs +24 -23
  107. package/hub/team/conductor.mjs +8 -4
  108. package/hub/team/dashboard-anchor.mjs +4 -5
  109. package/hub/team/dashboard-layout.mjs +3 -1
  110. package/hub/team/dashboard-open.mjs +41 -21
  111. package/hub/team/dashboard.mjs +76 -28
  112. package/hub/team/event-log.mjs +18 -10
  113. package/hub/team/handoff.mjs +31 -15
  114. package/hub/team/headless.mjs +2 -1
  115. package/hub/team/health-probe.mjs +69 -54
  116. package/hub/team/launcher-template.mjs +16 -13
  117. package/hub/team/native-supervisor.mjs +65 -21
  118. package/hub/team/native.mjs +74 -35
  119. package/hub/team/nativeProxy.mjs +184 -113
  120. package/hub/team/notify.mjs +120 -77
  121. package/hub/team/orchestrator.mjs +166 -161
  122. package/hub/team/pane.mjs +12 -7
  123. package/hub/team/process-cleanup.mjs +25 -16
  124. package/hub/team/psmux.mjs +491 -201
  125. package/hub/team/remote-probe.mjs +68 -52
  126. package/hub/team/remote-session.mjs +117 -59
  127. package/hub/team/remote-watcher.mjs +61 -33
  128. package/hub/team/routing.mjs +51 -25
  129. package/hub/team/runtime-strategy.mjs +3 -1
  130. package/hub/team/session.mjs +675 -611
  131. package/hub/team/shared.mjs +13 -13
  132. package/hub/team/staleState.mjs +72 -30
  133. package/hub/team/swarm-locks.mjs +15 -13
  134. package/hub/team/swarm-planner.mjs +32 -21
  135. package/hub/team/swarm-reconciler.mjs +48 -23
  136. package/hub/team/tui-lite.mjs +266 -68
  137. package/hub/team/tui-remote-adapter.mjs +14 -10
  138. package/hub/team/tui-viewer.mjs +99 -43
  139. package/hub/team/tui.mjs +708 -271
  140. package/hub/team/worktree-lifecycle.mjs +152 -58
  141. package/hub/team/wt-manager.mjs +24 -14
  142. package/hub/token-mode.mjs +71 -71
  143. package/hub/tray.mjs +411 -368
  144. package/hub/workers/claude-worker.mjs +162 -118
  145. package/hub/workers/codex-mcp.mjs +558 -507
  146. package/hub/workers/delegator-mcp.mjs +507 -333
  147. package/hub/workers/factory.mjs +21 -21
  148. package/hub/workers/gemini-worker.mjs +115 -84
  149. package/hub/workers/interface.mjs +6 -1
  150. package/hub/workers/worker-utils.mjs +21 -14
  151. package/hud/colors.mjs +27 -9
  152. package/hud/constants.mjs +162 -26
  153. package/hud/context-monitor.mjs +82 -41
  154. package/hud/hud-qos-status.mjs +129 -49
  155. package/hud/mission-board.mjs +6 -3
  156. package/hud/providers/claude.mjs +226 -115
  157. package/hud/providers/codex.mjs +62 -22
  158. package/hud/providers/gemini.mjs +168 -56
  159. package/hud/renderers.mjs +384 -119
  160. package/hud/terminal.mjs +101 -31
  161. package/hud/utils.mjs +78 -38
  162. package/mesh/index.mjs +11 -5
  163. package/mesh/mesh-budget.mjs +18 -9
  164. package/mesh/mesh-heartbeat.mjs +1 -1
  165. package/mesh/mesh-queue.mjs +3 -5
  166. package/mesh/mesh-router.mjs +5 -4
  167. package/package.json +56 -21
  168. package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
  169. package/scripts/__tests__/keyword-detector.test.mjs +77 -28
  170. package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
  171. package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
  172. package/scripts/__tests__/remote-spawn.test.mjs +10 -4
  173. package/scripts/__tests__/session-start-fast.test.mjs +36 -0
  174. package/scripts/__tests__/skill-template.test.mjs +98 -50
  175. package/scripts/__tests__/smoke.test.mjs +1 -1
  176. package/scripts/__tests__/spawn-trace.test.mjs +102 -0
  177. package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
  178. package/scripts/cache-doctor.mjs +11 -4
  179. package/scripts/cache-warmup.mjs +96 -37
  180. package/scripts/claudemd-sync.mjs +27 -17
  181. package/scripts/codex-gateway-preflight.mjs +52 -37
  182. package/scripts/codex-mcp-gateway-sync.mjs +59 -39
  183. package/scripts/config-audit.mjs +232 -0
  184. package/scripts/convert-to-tmpl.mjs +54 -0
  185. package/scripts/cross-review-gate.mjs +35 -12
  186. package/scripts/cross-review-tracker.mjs +21 -8
  187. package/scripts/demo.mjs +35 -17
  188. package/scripts/doctor-diagnose.mjs +284 -0
  189. package/scripts/gen-skill-docs.mjs +7 -2
  190. package/scripts/gen-skill-manifest.mjs +2 -1
  191. package/scripts/headless-guard.mjs +86 -48
  192. package/scripts/hub-ensure.mjs +139 -120
  193. package/scripts/keyword-detector.mjs +293 -272
  194. package/scripts/keyword-rules-expander.mjs +538 -521
  195. package/scripts/lib/claudemd-scanner.mjs +6 -1
  196. package/scripts/lib/context.mjs +3 -3
  197. package/scripts/lib/cross-review-utils.mjs +6 -3
  198. package/scripts/lib/env-probe.mjs +47 -28
  199. package/scripts/lib/gemini-profiles.mjs +44 -10
  200. package/scripts/lib/handoff.mjs +33 -17
  201. package/scripts/lib/hook-utils.mjs +8 -6
  202. package/scripts/lib/keyword-rules.mjs +43 -19
  203. package/scripts/lib/logger.mjs +24 -24
  204. package/scripts/lib/mcp-filter.mjs +377 -239
  205. package/scripts/lib/mcp-guard-engine.mjs +194 -79
  206. package/scripts/lib/mcp-manifest.mjs +23 -13
  207. package/scripts/lib/mcp-server-catalog.mjs +355 -118
  208. package/scripts/lib/psmux-info.mjs +11 -6
  209. package/scripts/lib/remote-spawn-transfer.mjs +44 -14
  210. package/scripts/lib/skill-template.mjs +30 -7
  211. package/scripts/mcp-check.mjs +58 -39
  212. package/scripts/mcp-gateway-config.mjs +83 -39
  213. package/scripts/mcp-gateway-ensure.mjs +43 -35
  214. package/scripts/mcp-gateway-integration-test.mjs +70 -58
  215. package/scripts/mcp-gateway-start.mjs +126 -60
  216. package/scripts/mcp-gateway-verify.mjs +24 -22
  217. package/scripts/mcp-safety-guard.mjs +44 -11
  218. package/scripts/notion-read.mjs +669 -554
  219. package/scripts/pack.mjs +94 -89
  220. package/scripts/preflight-cache.mjs +27 -10
  221. package/scripts/preinstall.mjs +42 -13
  222. package/scripts/remote-spawn.mjs +309 -94
  223. package/scripts/run.cjs +8 -5
  224. package/scripts/session-spawn-helper.mjs +130 -39
  225. package/scripts/session-stale-cleanup.mjs +123 -0
  226. package/scripts/setup.mjs +941 -492
  227. package/scripts/test-lock.mjs +20 -7
  228. package/scripts/test-tfx-route-no-claude-native.mjs +61 -57
  229. package/scripts/tfx-batch-stats.mjs +117 -96
  230. package/scripts/tfx-gate-activate.mjs +11 -4
  231. package/scripts/tfx-route-post.mjs +87 -20
  232. package/scripts/tfx-route-worker.mjs +57 -51
  233. package/scripts/tfx-route.sh +41 -124
  234. package/scripts/tmp-cleanup.mjs +21 -7
  235. package/scripts/token-snapshot.mjs +204 -85
  236. package/skills/.omc/state/idle-notif-cooldown.json +1 -1
  237. package/skills/.omc/state/last-tool-error.json +1 -1
  238. package/skills/.omc/state/subagent-tracking.json +1 -1
  239. package/skills/_templates/base.md +1 -6
  240. package/skills/merge-worktree/SKILL.md.tmpl +144 -0
  241. package/skills/shared/telemetry-segment.md +6 -0
  242. package/skills/star-prompt/SKILL.md.tmpl +222 -0
  243. package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
  244. package/skills/tfx-analysis/skill.json +1 -6
  245. package/skills/tfx-auto/SKILL.md +1 -0
  246. package/skills/{tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md → tfx-auto-codex/SKILL.md.tmpl} +33 -4
  247. package/skills/tfx-auto-codex/skill.json +1 -3
  248. package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
  249. package/skills/tfx-autopilot/skill.json +1 -5
  250. package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
  251. package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
  252. package/skills/tfx-autoroute/skill.json +1 -7
  253. package/skills/tfx-codex/SKILL.md +1 -0
  254. package/skills/tfx-codex/skill.json +1 -3
  255. package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
  256. package/skills/tfx-codex-swarm/evals/evals.json +1 -1
  257. package/skills/tfx-codex-swarm/skill.json +1 -4
  258. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
  259. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
  260. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
  261. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
  262. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
  263. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
  264. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
  265. package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
  266. package/skills/tfx-debate/SKILL.md.tmpl +192 -0
  267. package/skills/tfx-debate/skill.json +1 -7
  268. package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
  269. package/skills/tfx-deep-analysis/skill.json +1 -5
  270. package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
  271. package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
  272. package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
  273. package/skills/tfx-deep-qa/skill.json +1 -6
  274. package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
  275. package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
  276. package/skills/tfx-doctor/SKILL.md +21 -0
  277. package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
  278. package/skills/tfx-doctor/skill.json +1 -3
  279. package/skills/tfx-find/SKILL.md +1 -0
  280. package/skills/tfx-forge/SKILL.md.tmpl +187 -0
  281. package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
  282. package/skills/tfx-fullcycle/skill.json +1 -6
  283. package/skills/{tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md → tfx-gemini/SKILL.md.tmpl} +16 -7
  284. package/skills/tfx-gemini/skill.json +1 -3
  285. package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
  286. package/skills/tfx-hooks/skill.json +1 -3
  287. package/skills/tfx-hub/SKILL.md.tmpl +212 -0
  288. package/skills/tfx-hub/skill.json +1 -3
  289. package/skills/tfx-index/SKILL.md +1 -0
  290. package/skills/tfx-index/skill.json +1 -6
  291. package/skills/tfx-interview/SKILL.md.tmpl +285 -0
  292. package/skills/tfx-multi/SKILL.md.tmpl +183 -0
  293. package/skills/tfx-multi/skill.json +1 -3
  294. package/skills/tfx-panel/SKILL.md.tmpl +189 -0
  295. package/skills/tfx-panel/skill.json +1 -7
  296. package/skills/tfx-persist/SKILL.md.tmpl +270 -0
  297. package/skills/tfx-persist/skill.json +1 -7
  298. package/skills/tfx-plan/SKILL.md +1 -0
  299. package/skills/tfx-plan/skill.json +1 -6
  300. package/skills/tfx-profile/SKILL.md.tmpl +239 -0
  301. package/skills/tfx-profile/skill.json +1 -3
  302. package/skills/tfx-prune/SKILL.md.tmpl +200 -0
  303. package/skills/tfx-prune/skill.json +1 -7
  304. package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
  305. package/skills/tfx-psmux-rules/skill.json +1 -4
  306. package/skills/tfx-qa/SKILL.md +1 -0
  307. package/skills/tfx-qa/skill.json +1 -6
  308. package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
  309. package/skills/tfx-ralph/skill.json +1 -4
  310. package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
  311. package/skills/tfx-remote-setup/skill.json +1 -3
  312. package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
  313. package/skills/tfx-remote-spawn/references/hosts.json +16 -16
  314. package/skills/tfx-remote-spawn/skill.json +1 -4
  315. package/skills/tfx-research/SKILL.md +1 -0
  316. package/skills/tfx-review/SKILL.md +1 -0
  317. package/skills/tfx-review/skill.json +1 -6
  318. package/skills/tfx-setup/SKILL.md.tmpl +504 -0
  319. package/skills/tfx-setup/skill.json +1 -3
  320. package/skills/tfx-swarm/SKILL.md +22 -0
  321. package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
  322. package/tui/codex-profile.mjs +457 -0
  323. package/tui/core.mjs +266 -0
  324. package/tui/doctor.mjs +375 -0
  325. package/tui/gemini-profile.mjs +299 -0
  326. package/tui/monitor-data.mjs +152 -0
  327. package/tui/monitor.mjs +339 -0
  328. package/tui/setup.mjs +533 -0
  329. package/CLAUDE.md +0 -193
  330. package/references/hosts.json +0 -33
  331. package/skills/tfx-workspace/async-tests/run-tests.sh +0 -203
  332. package/skills/tfx-workspace/evals/evals.json +0 -79
  333. package/skills/tfx-workspace/iteration-1/benchmark.json +0 -162
  334. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +0 -11
  335. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +0 -9
  336. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +0 -154
  337. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +0 -5
  338. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +0 -9
  339. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +0 -126
  340. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +0 -5
  341. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +0 -11
  342. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +0 -9
  343. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +0 -119
  344. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +0 -5
  345. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +0 -9
  346. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +0 -115
  347. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +0 -5
  348. package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +0 -10
  349. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +0 -8
  350. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +0 -86
  351. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +0 -5
  352. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +0 -8
  353. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +0 -81
  354. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +0 -5
  355. package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +0 -12
  356. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +0 -10
  357. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +0 -316
  358. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +0 -5
  359. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +0 -10
  360. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +0 -352
  361. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +0 -5
  362. package/skills/tfx-workspace/iteration-1/review.html +0 -1325
  363. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +0 -12
  364. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +0 -10
  365. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +0 -97
  366. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +0 -5
  367. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +0 -10
  368. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +0 -94
  369. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +0 -5
  370. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +0 -12
  371. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +0 -10
  372. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +0 -209
  373. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +0 -5
  374. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +0 -10
  375. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +0 -193
  376. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +0 -5
  377. package/skills/tfx-workspace/iteration-2/benchmark.json +0 -62
  378. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +0 -13
  379. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +0 -11
  380. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +0 -382
  381. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +0 -5
  382. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +0 -11
  383. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +0 -333
  384. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +0 -5
  385. package/skills/tfx-workspace/iteration-2/review.html +0 -1325
  386. package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +0 -217
  387. package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +0 -65
  388. package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +0 -94
  389. package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +0 -133
  390. package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +0 -426
  391. package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +0 -101
@@ -1,9 +1,18 @@
1
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, copyFileSync, renameSync, lstatSync } from 'node:fs';
2
- import { basename, join, resolve } from 'node:path';
1
+ import {
2
+ copyFileSync,
3
+ existsSync,
4
+ lstatSync,
5
+ mkdirSync,
6
+ readdirSync,
7
+ readFileSync,
8
+ renameSync,
9
+ writeFileSync,
10
+ } from "node:fs";
11
+ import { basename, join, resolve } from "node:path";
3
12
 
4
13
  // ── Constants ──
5
14
 
6
- const SEVERITY = Object.freeze({ P0: 'P0', P1: 'P1', P2: 'P2' });
15
+ const SEVERITY = Object.freeze({ P0: "P0", P1: "P1", P2: "P2" });
7
16
  const WEIGHT = Object.freeze({ P0: 2.0, P1: 0.5, P2: 0.2 });
8
17
 
9
18
  const MEMORY_LINK_RE = /\[([^\]]*)\]\(([^)]+\.md)\)/gu;
@@ -27,34 +36,46 @@ const LATIN_RE = /[a-zA-Z]{3,}/u;
27
36
  const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
28
37
 
29
38
  function parseFrontmatter(content) {
30
- const match = FRONTMATTER_RE.exec(String(content || ''));
39
+ const match = FRONTMATTER_RE.exec(String(content || ""));
31
40
  if (!match) return { found: false, fields: {}, body: content };
32
41
 
33
42
  const fields = {};
34
- for (const line of match[1].split('\n')) {
35
- const sep = line.indexOf(':');
43
+ for (const line of match[1].split("\n")) {
44
+ const sep = line.indexOf(":");
36
45
  if (sep === -1) continue;
37
46
  const key = line.slice(0, sep).trim();
38
47
  const val = line.slice(sep + 1).trim();
39
48
  if (key) fields[key] = val;
40
49
  }
41
- return { found: true, fields, body: String(content).slice(match[0].length).trim() };
50
+ return {
51
+ found: true,
52
+ fields,
53
+ body: String(content).slice(match[0].length).trim(),
54
+ };
42
55
  }
43
56
 
44
57
  function safeReadFile(filePath) {
45
58
  try {
46
- return existsSync(filePath) ? readFileSync(filePath, 'utf8') : null;
47
- } catch { return null; }
59
+ return existsSync(filePath) ? readFileSync(filePath, "utf8") : null;
60
+ } catch {
61
+ return null;
62
+ }
48
63
  }
49
64
 
50
65
  function safeReadDir(dirPath) {
51
66
  try {
52
67
  return existsSync(dirPath) ? readdirSync(dirPath) : [];
53
- } catch { return []; }
68
+ } catch {
69
+ return [];
70
+ }
54
71
  }
55
72
 
56
73
  function isCI() {
57
- return process.env.CI === 'true' || process.env.DOCKER === 'true' || process.env.TFX_POSTINSTALL_FIX !== '1' && process.env.CI != null;
74
+ return (
75
+ process.env.CI === "true" ||
76
+ process.env.DOCKER === "true" ||
77
+ (process.env.TFX_POSTINSTALL_FIX !== "1" && process.env.CI != null)
78
+ );
58
79
  }
59
80
 
60
81
  function makeCheckResult(id, name, severity, autofix, issues, error = null) {
@@ -72,10 +93,16 @@ function makeCheckResult(id, name, severity, autofix, issues, error = null) {
72
93
  // ── Check Functions ──
73
94
 
74
95
  function checkOrphanFiles(memoryDir) {
75
- const indexPath = join(memoryDir, 'MEMORY.md');
96
+ const indexPath = join(memoryDir, "MEMORY.md");
76
97
  const indexContent = safeReadFile(indexPath);
77
98
  if (indexContent == null) {
78
- return makeCheckResult('orphan-files', '고아 파일 감지', SEVERITY.P0, true, []);
99
+ return makeCheckResult(
100
+ "orphan-files",
101
+ "고아 파일 감지",
102
+ SEVERITY.P0,
103
+ true,
104
+ [],
105
+ );
79
106
  }
80
107
 
81
108
  const indexed = new Set();
@@ -85,18 +112,25 @@ function checkOrphanFiles(memoryDir) {
85
112
  indexed.add(m[2]);
86
113
  }
87
114
 
88
- const diskFiles = safeReadDir(memoryDir)
89
- .filter(f => f.endsWith('.md') && f !== 'MEMORY.md');
115
+ const diskFiles = safeReadDir(memoryDir).filter(
116
+ (f) => f.endsWith(".md") && f !== "MEMORY.md",
117
+ );
90
118
 
91
119
  const orphans = diskFiles
92
- .filter(f => !indexed.has(f))
93
- .map(f => ({ file: f, detail: 'MEMORY.md 인덱스에 미등록' }));
94
-
95
- return makeCheckResult('orphan-files', '고아 파일 감지', SEVERITY.P0, true, orphans);
120
+ .filter((f) => !indexed.has(f))
121
+ .map((f) => ({ file: f, detail: "MEMORY.md 인덱스에 미등록" }));
122
+
123
+ return makeCheckResult(
124
+ "orphan-files",
125
+ "고아 파일 감지",
126
+ SEVERITY.P0,
127
+ true,
128
+ orphans,
129
+ );
96
130
  }
97
131
 
98
132
  function checkPathsYamlBug(rulesDir) {
99
- const files = safeReadDir(rulesDir).filter(f => f.endsWith('.md'));
133
+ const files = safeReadDir(rulesDir).filter((f) => f.endsWith(".md"));
100
134
  const issues = [];
101
135
 
102
136
  for (const file of files) {
@@ -108,46 +142,73 @@ function checkPathsYamlBug(rulesDir) {
108
142
 
109
143
  const rawFm = FRONTMATTER_RE.exec(content);
110
144
  if (rawFm && PATHS_YAML_RE.test(rawFm[1])) {
111
- issues.push({ file, detail: 'paths: YAML 배열 사용 (동작 안 함 — globs: CSV로 변환 필요)' });
145
+ issues.push({
146
+ file,
147
+ detail: "paths: YAML 배열 사용 (동작 안 함 — globs: CSV로 변환 필요)",
148
+ });
112
149
  }
113
150
  }
114
151
 
115
- return makeCheckResult('paths-yaml-bug', 'paths: YAML 배열 버그', SEVERITY.P0, true, issues);
152
+ return makeCheckResult(
153
+ "paths-yaml-bug",
154
+ "paths: YAML 배열 버그",
155
+ SEVERITY.P0,
156
+ true,
157
+ issues,
158
+ );
116
159
  }
117
160
 
118
161
  function checkTrifluxResidue(projectDir, claudeDir) {
119
162
  const issues = [];
120
163
 
121
- const omcState = join(projectDir, '.omc', 'state');
164
+ const omcState = join(projectDir, ".omc", "state");
122
165
  if (existsSync(omcState)) {
123
166
  const now = Date.now();
124
167
  const staleThreshold = 7 * 24 * 60 * 60 * 1000;
125
- for (const f of safeReadDir(omcState).filter(f => f.endsWith('.json'))) {
168
+ for (const f of safeReadDir(omcState).filter((f) => f.endsWith(".json"))) {
126
169
  try {
127
170
  const stat = lstatSync(join(omcState, f));
128
171
  if (now - stat.mtimeMs > staleThreshold) {
129
- issues.push({ file: `.omc/state/${f}`, detail: '7일 이상 된 stale state 파일' });
172
+ issues.push({
173
+ file: `.omc/state/${f}`,
174
+ detail: "7일 이상 된 stale state 파일",
175
+ });
130
176
  }
131
- } catch { /* skip */ }
177
+ } catch {
178
+ /* skip */
179
+ }
132
180
  }
133
181
  }
134
182
 
135
- const scriptsDir = join(claudeDir, 'scripts');
183
+ const scriptsDir = join(claudeDir, "scripts");
136
184
  for (const f of safeReadDir(scriptsDir)) {
137
185
  try {
138
186
  const fullPath = join(scriptsDir, f);
139
187
  const stat = lstatSync(fullPath);
140
188
  if (stat.isSymbolicLink() && !existsSync(fullPath)) {
141
- issues.push({ file: `~/.claude/scripts/${f}`, detail: '깨진 심볼릭 링크' });
189
+ issues.push({
190
+ file: `~/.claude/scripts/${f}`,
191
+ detail: "깨진 심볼릭 링크",
192
+ });
142
193
  }
143
- } catch { /* skip */ }
194
+ } catch {
195
+ /* skip */
196
+ }
144
197
  }
145
198
 
146
- return makeCheckResult('triflux-residue', '기존 triflux 잔재', SEVERITY.P0, true, issues);
199
+ return makeCheckResult(
200
+ "triflux-residue",
201
+ "기존 triflux 잔재",
202
+ SEVERITY.P0,
203
+ true,
204
+ issues,
205
+ );
147
206
  }
148
207
 
149
208
  function checkRuleViolation(memoryDir) {
150
- const files = safeReadDir(memoryDir).filter(f => f.endsWith('.md') && f !== 'MEMORY.md');
209
+ const files = safeReadDir(memoryDir).filter(
210
+ (f) => f.endsWith(".md") && f !== "MEMORY.md",
211
+ );
151
212
  const issues = [];
152
213
 
153
214
  for (const file of files) {
@@ -156,17 +217,25 @@ function checkRuleViolation(memoryDir) {
156
217
 
157
218
  for (const pattern of RULE_VIOLATION_PATTERNS) {
158
219
  if (pattern.test(content)) {
159
- issues.push({ file, detail: '코드에서 도출 가능한 정보 포함' });
220
+ issues.push({ file, detail: "코드에서 도출 가능한 정보 포함" });
160
221
  break;
161
222
  }
162
223
  }
163
224
  }
164
225
 
165
- return makeCheckResult('rule-violation', '저장 규칙 위반', SEVERITY.P1, false, issues);
226
+ return makeCheckResult(
227
+ "rule-violation",
228
+ "저장 규칙 위반",
229
+ SEVERITY.P1,
230
+ false,
231
+ issues,
232
+ );
166
233
  }
167
234
 
168
235
  function checkStaleReferences(memoryDir, projectDir) {
169
- const files = safeReadDir(memoryDir).filter(f => f.endsWith('.md') && f !== 'MEMORY.md');
236
+ const files = safeReadDir(memoryDir).filter(
237
+ (f) => f.endsWith(".md") && f !== "MEMORY.md",
238
+ );
170
239
  const issues = [];
171
240
  const fileRefRe = /(?:^|\s)([a-zA-Z][\w/.%-]+\.[a-z]{1,5})(?::(\d+))?/gu;
172
241
 
@@ -178,19 +247,32 @@ function checkStaleReferences(memoryDir, projectDir) {
178
247
  const re = new RegExp(fileRefRe.source, fileRefRe.flags);
179
248
  while ((m = re.exec(content)) !== null) {
180
249
  const refPath = m[1];
181
- if (refPath.startsWith('http') || refPath.startsWith('node:') || refPath.includes('node_modules')) continue;
250
+ if (
251
+ refPath.startsWith("http") ||
252
+ refPath.startsWith("node:") ||
253
+ refPath.includes("node_modules")
254
+ )
255
+ continue;
182
256
  const fullPath = resolve(projectDir, refPath);
183
- if (!existsSync(fullPath) && refPath.includes('/')) {
257
+ if (!existsSync(fullPath) && refPath.includes("/")) {
184
258
  issues.push({ file, detail: `존재하지 않는 파일 참조: ${refPath}` });
185
259
  }
186
260
  }
187
261
  }
188
262
 
189
- return makeCheckResult('stale-references', 'stale 참조', SEVERITY.P1, false, issues);
263
+ return makeCheckResult(
264
+ "stale-references",
265
+ "stale 참조",
266
+ SEVERITY.P1,
267
+ false,
268
+ issues,
269
+ );
190
270
  }
191
271
 
192
272
  function checkLanguageInconsistency(memoryDir) {
193
- const files = safeReadDir(memoryDir).filter(f => f.endsWith('.md') && f !== 'MEMORY.md');
273
+ const files = safeReadDir(memoryDir).filter(
274
+ (f) => f.endsWith(".md") && f !== "MEMORY.md",
275
+ );
194
276
  const issues = [];
195
277
 
196
278
  let koCount = 0;
@@ -202,16 +284,16 @@ function checkLanguageInconsistency(memoryDir) {
202
284
  const fm = parseFrontmatter(content);
203
285
  if (!fm.found) continue;
204
286
 
205
- const nameVal = fm.fields.name || '';
206
- const descVal = fm.fields.description || '';
287
+ const nameVal = fm.fields.name || "";
288
+ const descVal = fm.fields.description || "";
207
289
  const combined = `${nameVal} ${descVal}`;
208
290
 
209
291
  if (HANGUL_RE.test(combined)) koCount++;
210
292
  else if (LATIN_RE.test(combined)) enCount++;
211
293
  }
212
294
 
213
- const majorLang = koCount >= enCount ? 'ko' : 'en';
214
- const isKoMajor = majorLang === 'ko';
295
+ const majorLang = koCount >= enCount ? "ko" : "en";
296
+ const isKoMajor = majorLang === "ko";
215
297
 
216
298
  for (const file of files) {
217
299
  const content = safeReadFile(join(memoryDir, file));
@@ -219,7 +301,7 @@ function checkLanguageInconsistency(memoryDir) {
219
301
  const fm = parseFrontmatter(content);
220
302
  if (!fm.found || !fm.fields.name) continue;
221
303
 
222
- const combined = `${fm.fields.name} ${fm.fields.description || ''}`;
304
+ const combined = `${fm.fields.name} ${fm.fields.description || ""}`;
223
305
  const hasKo = HANGUL_RE.test(combined);
224
306
  const hasEn = LATIN_RE.test(combined);
225
307
 
@@ -230,47 +312,75 @@ function checkLanguageInconsistency(memoryDir) {
230
312
  }
231
313
  }
232
314
 
233
- return makeCheckResult('language-inconsistency', '언어 혼용', SEVERITY.P2, false, issues);
315
+ return makeCheckResult(
316
+ "language-inconsistency",
317
+ "언어 혼용",
318
+ SEVERITY.P2,
319
+ false,
320
+ issues,
321
+ );
234
322
  }
235
323
 
236
324
  function checkOversizedFiles(memoryDir) {
237
- const files = safeReadDir(memoryDir).filter(f => f.endsWith('.md') && f !== 'MEMORY.md');
325
+ const files = safeReadDir(memoryDir).filter(
326
+ (f) => f.endsWith(".md") && f !== "MEMORY.md",
327
+ );
238
328
  const issues = [];
239
329
 
240
330
  for (const file of files) {
241
331
  const content = safeReadFile(join(memoryDir, file));
242
332
  if (content == null) continue;
243
- const lineCount = content.split('\n').length;
333
+ const lineCount = content.split("\n").length;
244
334
  if (lineCount > 50) {
245
335
  issues.push({ file, detail: `${lineCount}줄 (50줄 초과)` });
246
336
  }
247
337
  }
248
338
 
249
- return makeCheckResult('oversized-files', '과대 파일', SEVERITY.P2, false, issues);
339
+ return makeCheckResult(
340
+ "oversized-files",
341
+ "과대 파일",
342
+ SEVERITY.P2,
343
+ false,
344
+ issues,
345
+ );
250
346
  }
251
347
 
252
348
  function checkMissingUserMemory(memoryDir) {
253
- const files = safeReadDir(memoryDir).filter(f => f.endsWith('.md') && f !== 'MEMORY.md');
349
+ const files = safeReadDir(memoryDir).filter(
350
+ (f) => f.endsWith(".md") && f !== "MEMORY.md",
351
+ );
254
352
  const issues = [];
255
353
 
256
- const hasUserType = files.some(file => {
354
+ const hasUserType = files.some((file) => {
257
355
  const content = safeReadFile(join(memoryDir, file));
258
356
  if (content == null) return false;
259
357
  const fm = parseFrontmatter(content);
260
- return fm.found && fm.fields.type === 'user';
358
+ return fm.found && fm.fields.type === "user";
261
359
  });
262
360
 
263
361
  if (!hasUserType && files.length > 0) {
264
- issues.push({ file: 'memory/', detail: 'type: user 메모리 파일 없음 — 사용자 프로필 미등록' });
362
+ issues.push({
363
+ file: "memory/",
364
+ detail: "type: user 메모리 파일 없음 — 사용자 프로필 미등록",
365
+ });
265
366
  }
266
367
 
267
- return makeCheckResult('missing-user-memory', 'user 타입 메모리 부재', SEVERITY.P2, true, issues);
368
+ return makeCheckResult(
369
+ "missing-user-memory",
370
+ "user 타입 메모리 부재",
371
+ SEVERITY.P2,
372
+ true,
373
+ issues,
374
+ );
268
375
  }
269
376
 
270
377
  // ── Fix Functions ──
271
378
 
272
379
  function createBackup(files, backupDir) {
273
- const timestamp = new Date().toISOString().replace(/[:.]/gu, '-').slice(0, 19);
380
+ const timestamp = new Date()
381
+ .toISOString()
382
+ .replace(/[:.]/gu, "-")
383
+ .slice(0, 19);
274
384
  const dir = join(backupDir, timestamp);
275
385
  mkdirSync(dir, { recursive: true });
276
386
 
@@ -282,32 +392,44 @@ function createBackup(files, backupDir) {
282
392
  backed.push({ src, dst });
283
393
  }
284
394
 
285
- writeFileSync(join(dir, 'manifest.json'), JSON.stringify({
286
- timestamp,
287
- files: backed,
288
- restore: 'tfx memory-doctor --undo',
289
- }, null, 2), 'utf8');
395
+ writeFileSync(
396
+ join(dir, "manifest.json"),
397
+ JSON.stringify(
398
+ {
399
+ timestamp,
400
+ files: backed,
401
+ restore: "tfx memory-doctor --undo",
402
+ },
403
+ null,
404
+ 2,
405
+ ),
406
+ "utf8",
407
+ );
290
408
 
291
409
  return { dir, files: backed };
292
410
  }
293
411
 
294
412
  function fixOrphanFiles(memoryDir, issues) {
295
- const indexPath = join(memoryDir, 'MEMORY.md');
413
+ const indexPath = join(memoryDir, "MEMORY.md");
296
414
  const content = safeReadFile(indexPath);
297
- if (content == null) return { action: 'skipped', fixed: [] };
415
+ if (content == null) return { action: "skipped", fixed: [] };
298
416
 
299
417
  const additions = issues.map(({ file }) => {
300
- const fm = parseFrontmatter(safeReadFile(join(memoryDir, file)) || '');
301
- const desc = fm.fields.description || '(설명 없음)';
418
+ const fm = parseFrontmatter(safeReadFile(join(memoryDir, file)) || "");
419
+ const desc = fm.fields.description || "(설명 없음)";
302
420
  return `- [${fm.fields.name || file}](${file}) — ${desc}`;
303
421
  });
304
422
 
305
- if (additions.length === 0) return { action: 'unchanged', fixed: [] };
423
+ if (additions.length === 0) return { action: "unchanged", fixed: [] };
306
424
 
307
- const separator = content.endsWith('\n') ? '' : '\n';
308
- writeFileSync(indexPath, `${content}${separator}${additions.join('\n')}\n`, 'utf8');
425
+ const separator = content.endsWith("\n") ? "" : "\n";
426
+ writeFileSync(
427
+ indexPath,
428
+ `${content}${separator}${additions.join("\n")}\n`,
429
+ "utf8",
430
+ );
309
431
 
310
- return { action: 'fixed', fixed: issues.map(i => i.file) };
432
+ return { action: "fixed", fixed: issues.map((i) => i.file) };
311
433
  }
312
434
 
313
435
  function fixPathsYamlBug(rulesDir, issues) {
@@ -326,21 +448,24 @@ function fixPathsYamlBug(rulesDir, issues) {
326
448
  if (!pathsMatch) continue;
327
449
 
328
450
  const values = [];
329
- for (const line of pathsMatch[0].split('\n')) {
330
- const trimmed = line.replace(/^\s*-\s*/, '').replace(/^["']|["']$/gu, '').trim();
331
- if (trimmed && trimmed !== 'paths:') values.push(trimmed);
451
+ for (const line of pathsMatch[0].split("\n")) {
452
+ const trimmed = line
453
+ .replace(/^\s*-\s*/, "")
454
+ .replace(/^["']|["']$/gu, "")
455
+ .trim();
456
+ if (trimmed && trimmed !== "paths:") values.push(trimmed);
332
457
  }
333
458
 
334
459
  if (values.length === 0) continue;
335
460
 
336
- const globsLine = `globs: ${values.join(', ')}`;
461
+ const globsLine = `globs: ${values.join(", ")}`;
337
462
  const nextFm = fmRaw.replace(pathsMatch[0], globsLine);
338
463
  const nextContent = `---\n${nextFm}\n---${content.slice(fmMatch[0].length)}`;
339
- writeFileSync(filePath, nextContent, 'utf8');
464
+ writeFileSync(filePath, nextContent, "utf8");
340
465
  fixed.push(file);
341
466
  }
342
467
 
343
- return { action: fixed.length > 0 ? 'fixed' : 'unchanged', fixed };
468
+ return { action: fixed.length > 0 ? "fixed" : "unchanged", fixed };
344
469
  }
345
470
 
346
471
  function fixTrifluxResidue(issues) {
@@ -348,17 +473,21 @@ function fixTrifluxResidue(issues) {
348
473
 
349
474
  for (const { file } of issues) {
350
475
  try {
351
- const fullPath = resolve(file.replace(/^~\/\.claude/u, join(process.env.HOME || '', '.claude')));
476
+ const fullPath = resolve(
477
+ file.replace(/^~\/\.claude/u, join(process.env.HOME || "", ".claude")),
478
+ );
352
479
  if (!existsSync(fullPath)) continue;
353
480
 
354
- const archiveDir = join(resolve('.tfx', 'archive'));
481
+ const archiveDir = join(resolve(".tfx", "archive"));
355
482
  mkdirSync(archiveDir, { recursive: true });
356
483
  renameSync(fullPath, join(archiveDir, basename(fullPath)));
357
484
  fixed.push(file);
358
- } catch { /* skip unresolvable */ }
485
+ } catch {
486
+ /* skip unresolvable */
487
+ }
359
488
  }
360
489
 
361
- return { action: fixed.length > 0 ? 'fixed' : 'unchanged', fixed };
490
+ return { action: fixed.length > 0 ? "fixed" : "unchanged", fixed };
362
491
  }
363
492
 
364
493
  // ── Health Score ──
@@ -388,20 +517,22 @@ const ALL_CHECKS = [
388
517
  ];
389
518
 
390
519
  const FIX_MAP = {
391
- 'orphan-files': fixOrphanFiles,
392
- 'paths-yaml-bug': fixPathsYamlBug,
393
- 'triflux-residue': fixTrifluxResidue,
520
+ "orphan-files": fixOrphanFiles,
521
+ "paths-yaml-bug": fixPathsYamlBug,
522
+ "triflux-residue": fixTrifluxResidue,
394
523
  };
395
524
 
396
525
  export function createMemoryDoctor(options = {}) {
397
- const memoryDir = resolve(options.memoryDir || '');
398
- const rulesDir = resolve(options.rulesDir || '');
526
+ const memoryDir = resolve(options.memoryDir || "");
527
+ const rulesDir = resolve(options.rulesDir || "");
399
528
  const projectDir = resolve(options.projectDir || process.cwd());
400
- const claudeDir = resolve(options.claudeDir || '');
401
- const backupDir = resolve(options.backupDir || join(projectDir, '.tfx', 'backups'));
529
+ const claudeDir = resolve(options.claudeDir || "");
530
+ const backupDir = resolve(
531
+ options.backupDir || join(projectDir, ".tfx", "backups"),
532
+ );
402
533
 
403
534
  function scan() {
404
- const checks = ALL_CHECKS.map(fn => {
535
+ const checks = ALL_CHECKS.map((fn) => {
405
536
  try {
406
537
  if (fn === checkOrphanFiles) return fn(memoryDir);
407
538
  if (fn === checkPathsYamlBug) return fn(rulesDir);
@@ -413,16 +544,26 @@ export function createMemoryDoctor(options = {}) {
413
544
  if (fn === checkMissingUserMemory) return fn(memoryDir);
414
545
  return fn(memoryDir);
415
546
  } catch (err) {
416
- return makeCheckResult(fn.name.replace('check', '').replace(/([A-Z])/gu, '-$1').toLowerCase().replace(/^-/u, ''),
417
- fn.name, SEVERITY.P2, false, [], err.message);
547
+ return makeCheckResult(
548
+ fn.name
549
+ .replace("check", "")
550
+ .replace(/([A-Z])/gu, "-$1")
551
+ .toLowerCase()
552
+ .replace(/^-/u, ""),
553
+ fn.name,
554
+ SEVERITY.P2,
555
+ false,
556
+ [],
557
+ err.message,
558
+ );
418
559
  }
419
560
  });
420
561
 
421
562
  const healthScore = computeHealthScore(checks);
422
563
  const summary = {
423
- p0: checks.filter(c => c.severity === SEVERITY.P0 && !c.passed).length,
424
- p1: checks.filter(c => c.severity === SEVERITY.P1 && !c.passed).length,
425
- p2: checks.filter(c => c.severity === SEVERITY.P2 && !c.passed).length,
564
+ p0: checks.filter((c) => c.severity === SEVERITY.P0 && !c.passed).length,
565
+ p1: checks.filter((c) => c.severity === SEVERITY.P1 && !c.passed).length,
566
+ p2: checks.filter((c) => c.severity === SEVERITY.P2 && !c.passed).length,
426
567
  };
427
568
 
428
569
  return Object.freeze({ checks, healthScore, summary });
@@ -430,30 +571,44 @@ export function createMemoryDoctor(options = {}) {
430
571
 
431
572
  function fix(checkId, opts = {}) {
432
573
  if (isCI() && !opts.force) {
433
- return { action: 'skipped_ci', backup: null, fixed: [] };
574
+ return { action: "skipped_ci", backup: null, fixed: [] };
434
575
  }
435
576
 
436
577
  const { checks } = scan();
437
- const check = checks.find(c => c.id === checkId);
438
- if (!check || check.passed) return { action: 'no_issues', backup: null, fixed: [] };
439
- if (!check.autofix) return { action: 'manual_only', backup: null, fixed: [] };
578
+ const check = checks.find((c) => c.id === checkId);
579
+ if (!check || check.passed)
580
+ return { action: "no_issues", backup: null, fixed: [] };
581
+ if (!check.autofix)
582
+ return { action: "manual_only", backup: null, fixed: [] };
440
583
 
441
584
  const fixFn = FIX_MAP[checkId];
442
- if (!fixFn) return { action: 'no_fixer', backup: null, fixed: [] };
585
+ if (!fixFn) return { action: "no_fixer", backup: null, fixed: [] };
443
586
 
444
587
  const affectedFiles = check.issues
445
- .map(i => {
446
- const candidate = join(checkId === 'orphan-files' ? memoryDir : rulesDir, i.file);
588
+ .map((i) => {
589
+ const candidate = join(
590
+ checkId === "orphan-files" ? memoryDir : rulesDir,
591
+ i.file,
592
+ );
447
593
  return existsSync(candidate) ? candidate : null;
448
594
  })
449
595
  .filter(Boolean);
450
596
 
451
- const indexFile = checkId === 'orphan-files' ? join(memoryDir, 'MEMORY.md') : null;
452
- const backupFiles = indexFile ? [indexFile, ...affectedFiles] : affectedFiles;
453
-
454
- const backup = backupFiles.length > 0 ? createBackup(backupFiles, backupDir) : null;
455
-
456
- const dir = checkId === 'orphan-files' ? memoryDir : checkId === 'paths-yaml-bug' ? rulesDir : projectDir;
597
+ const indexFile =
598
+ checkId === "orphan-files" ? join(memoryDir, "MEMORY.md") : null;
599
+ const backupFiles = indexFile
600
+ ? [indexFile, ...affectedFiles]
601
+ : affectedFiles;
602
+
603
+ const backup =
604
+ backupFiles.length > 0 ? createBackup(backupFiles, backupDir) : null;
605
+
606
+ const dir =
607
+ checkId === "orphan-files"
608
+ ? memoryDir
609
+ : checkId === "paths-yaml-bug"
610
+ ? rulesDir
611
+ : projectDir;
457
612
  const result = fixFn(dir, check.issues);
458
613
 
459
614
  return { ...result, backup: backup?.dir || null };
@@ -465,16 +620,21 @@ export function createMemoryDoctor(options = {}) {
465
620
  }
466
621
 
467
622
  const { checks } = scan();
468
- const targets = checks.filter(c => {
623
+ const targets = checks.filter((c) => {
469
624
  if (opts.severity && c.severity !== opts.severity) return false;
470
625
  return c.autofix && !c.passed;
471
626
  });
472
627
 
473
- const results = targets.map(c => ({ id: c.id, ...fix(c.id, opts) }));
628
+ const results = targets.map((c) => ({ id: c.id, ...fix(c.id, opts) }));
474
629
  return { results };
475
630
  }
476
631
 
477
- return Object.freeze({ scan, fix, fixAll, getHealthScore: computeHealthScore });
632
+ return Object.freeze({
633
+ scan,
634
+ fix,
635
+ fixAll,
636
+ getHealthScore: computeHealthScore,
637
+ });
478
638
  }
479
639
 
480
- export { computeHealthScore, parseFrontmatter, isCI };
640
+ export { computeHealthScore, isCI, parseFrontmatter };