@hassangameryt/freeflow 0.2.0 → 0.3.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 (639) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +2 -2
  3. package/{plugins/freeflow/.claude-plugin → .claude-plugin}/plugin.json +1 -1
  4. package/{plugins/freeflow/.codex-plugin → .codex-plugin}/plugin.json +1 -1
  5. package/README.md +19 -14
  6. package/assets/freeflow-plugin-icon.png +0 -0
  7. package/{plugins/freeflow/command-surface.json → command-surface.json} +10 -2
  8. package/evals/README.md +32 -0
  9. package/evals/fixtures/copy-conventions.md +31 -0
  10. package/evals/fixtures/output-router/README.md +12 -0
  11. package/evals/fixtures/output-router/failed-command-output.txt +9 -0
  12. package/evals/fixtures/output-router/large-router-manual.md +63 -0
  13. package/evals/fixtures/output-router/native-large-output.txt +40 -0
  14. package/evals/fixtures/output-router/noisy-test-output.txt +30 -0
  15. package/evals/fixtures/output-router/verification-output.txt +8 -0
  16. package/evals/fixtures/tiny-artifact-review-app/README.md +5 -0
  17. package/evals/fixtures/tiny-artifact-review-app/docs/billing-policy.md +10 -0
  18. package/evals/fixtures/tiny-artifact-review-app/docs/specs/billing-webhook-api-draft.md +21 -0
  19. package/evals/fixtures/tiny-artifact-review-app/docs/specs/failed-payment-grace-period.md +24 -0
  20. package/evals/fixtures/tiny-artifact-review-app/docs/specs/immediate-downgrade.md +17 -0
  21. package/evals/fixtures/tiny-artifact-review-app/tests/billing.test.md +8 -0
  22. package/evals/fixtures/tiny-commit-ambiguous-app/.freeflow-eval-setup.sh +15 -0
  23. package/evals/fixtures/tiny-commit-ambiguous-app/README.md +3 -0
  24. package/evals/fixtures/tiny-commit-ambiguous-app/src/billing.ts +5 -0
  25. package/evals/fixtures/tiny-commit-ambiguous-app/src/settings-page.ts +1 -0
  26. package/evals/fixtures/tiny-commit-ambiguous-app/tests/settings.test.md +5 -0
  27. package/evals/fixtures/tiny-commit-app/.freeflow-eval-setup.sh +14 -0
  28. package/evals/fixtures/tiny-commit-app/README.md +3 -0
  29. package/evals/fixtures/tiny-commit-app/docs/specs/settings-title.md +5 -0
  30. package/evals/fixtures/tiny-commit-app/src/billing.ts +5 -0
  31. package/evals/fixtures/tiny-commit-app/src/settings-page.ts +1 -0
  32. package/evals/fixtures/tiny-commit-app/tests/settings.test.md +5 -0
  33. package/evals/fixtures/tiny-commit-everything-app/.freeflow-eval-setup.sh +15 -0
  34. package/evals/fixtures/tiny-commit-everything-app/README.md +3 -0
  35. package/evals/fixtures/tiny-commit-everything-app/docs/specs/settings-title.md +5 -0
  36. package/evals/fixtures/tiny-commit-everything-app/src/billing.ts +5 -0
  37. package/evals/fixtures/tiny-commit-everything-app/src/settings-page.ts +1 -0
  38. package/evals/fixtures/tiny-commit-everything-app/tests/settings.test.md +5 -0
  39. package/evals/fixtures/tiny-commit-staged-app/.freeflow-eval-setup.sh +15 -0
  40. package/evals/fixtures/tiny-commit-staged-app/README.md +3 -0
  41. package/evals/fixtures/tiny-commit-staged-app/docs/specs/settings-title.md +5 -0
  42. package/evals/fixtures/tiny-commit-staged-app/src/billing.ts +5 -0
  43. package/evals/fixtures/tiny-commit-staged-app/src/settings-page.ts +1 -0
  44. package/evals/fixtures/tiny-commit-staged-app/tests/settings.test.md +5 -0
  45. package/evals/fixtures/tiny-commit-staged-mixed-app/.freeflow-eval-setup.sh +15 -0
  46. package/evals/fixtures/tiny-commit-staged-mixed-app/README.md +3 -0
  47. package/evals/fixtures/tiny-commit-staged-mixed-app/docs/billing-policy.md +3 -0
  48. package/evals/fixtures/tiny-commit-staged-mixed-app/docs/release-notes.md +3 -0
  49. package/evals/fixtures/tiny-commit-staged-mixed-app/src/billing.ts +5 -0
  50. package/evals/fixtures/tiny-dashboard-stale-app/README.md +11 -0
  51. package/evals/fixtures/tiny-dashboard-stale-app/src/api-client.ts +13 -0
  52. package/evals/fixtures/tiny-dashboard-stale-app/src/dashboard-data.ts +19 -0
  53. package/evals/fixtures/tiny-dashboard-stale-app/tests/dashboard-data.test.md +9 -0
  54. package/evals/fixtures/tiny-decision-destination-app/README.md +6 -0
  55. package/evals/fixtures/tiny-decision-destination-app/src/risk.ts +8 -0
  56. package/evals/fixtures/tiny-decision-destination-app/tests/risk.test.md +4 -0
  57. package/evals/fixtures/tiny-design-depth-app/README.md +15 -0
  58. package/evals/fixtures/tiny-design-depth-app/src/routes.ts +25 -0
  59. package/evals/fixtures/tiny-design-depth-app/src/sendEmail.ts +3 -0
  60. package/evals/fixtures/tiny-design-depth-app/src/sendSms.ts +3 -0
  61. package/evals/fixtures/tiny-design-depth-app/src/telemetry.ts +3 -0
  62. package/evals/fixtures/tiny-design-depth-app/tests/routes.test.md +12 -0
  63. package/evals/fixtures/tiny-eval-method-app/README.md +8 -0
  64. package/evals/fixtures/tiny-eval-method-app/evals/reports/review-pr-eval-result.md +5 -0
  65. package/evals/fixtures/tiny-eval-method-app/evals/reports/triage-question-failure.md +17 -0
  66. package/evals/fixtures/tiny-eval-method-app/evals/runs/review-pr-with-skill-output.diff +11 -0
  67. package/evals/fixtures/tiny-eval-method-app/evals/runs/review-pr-with-skill-output.md +3 -0
  68. package/evals/fixtures/tiny-eval-method-app/skills/review-pr/SKILL.md +10 -0
  69. package/evals/fixtures/tiny-eval-method-app/skills/triage-question/SKILL.md +10 -0
  70. package/evals/fixtures/tiny-execute-plan-app/README.md +5 -0
  71. package/evals/fixtures/tiny-execute-plan-app/checks/settings-and-billing-check.sh +5 -0
  72. package/evals/fixtures/tiny-execute-plan-app/docs/billing-policy.md +10 -0
  73. package/evals/fixtures/tiny-execute-plan-app/docs/plans/immediate-downgrade-plan.md +11 -0
  74. package/evals/fixtures/tiny-execute-plan-app/docs/plans/settings-title-plan.md +12 -0
  75. package/evals/fixtures/tiny-execute-plan-app/docs/plans/settings-title-with-bad-check.md +15 -0
  76. package/evals/fixtures/tiny-execute-plan-app/docs/plans/unverified-billing-plan.md +9 -0
  77. package/evals/fixtures/tiny-execute-plan-app/docs/specs/failed-payment-grace-period.md +9 -0
  78. package/evals/fixtures/tiny-execute-plan-app/docs/specs/settings-title.md +9 -0
  79. package/evals/fixtures/tiny-execute-plan-app/src/billing.ts +7 -0
  80. package/evals/fixtures/tiny-execute-plan-app/src/settings-page.ts +1 -0
  81. package/evals/fixtures/tiny-execute-plan-app/tests/billing.test.md +7 -0
  82. package/evals/fixtures/tiny-execute-plan-app/tests/settings.test.md +5 -0
  83. package/evals/fixtures/tiny-execute-review-loop-app/README.md +5 -0
  84. package/evals/fixtures/tiny-execute-review-loop-app/docs/billing-policy.md +9 -0
  85. package/evals/fixtures/tiny-execute-review-loop-app/docs/plans/settings-title-plan.md +12 -0
  86. package/evals/fixtures/tiny-execute-review-loop-app/docs/review/previous-agent-summary.md +15 -0
  87. package/evals/fixtures/tiny-execute-review-loop-app/docs/review/review-pass-1-non-pass.md +11 -0
  88. package/evals/fixtures/tiny-execute-review-loop-app/docs/specs/settings-title.md +9 -0
  89. package/evals/fixtures/tiny-execute-review-loop-app/src/billing.ts +7 -0
  90. package/evals/fixtures/tiny-execute-review-loop-app/src/settings-page.ts +1 -0
  91. package/evals/fixtures/tiny-execute-review-loop-app/tests/billing.test.md +7 -0
  92. package/evals/fixtures/tiny-execute-review-loop-app/tests/settings.test.md +5 -0
  93. package/evals/fixtures/tiny-flaky-session-app/README.md +10 -0
  94. package/evals/fixtures/tiny-flaky-session-app/src/session-timeout.ts +13 -0
  95. package/evals/fixtures/tiny-flaky-session-app/tests/session-timeout.test.md +8 -0
  96. package/evals/fixtures/tiny-handoff-app/README.md +5 -0
  97. package/evals/fixtures/tiny-handoff-app/docs/billing-policy.md +10 -0
  98. package/evals/fixtures/tiny-handoff-app/docs/handoffs/old-agent-handoff.md +8 -0
  99. package/evals/fixtures/tiny-handoff-app/docs/plans/billing-retry-plan.md +11 -0
  100. package/evals/fixtures/tiny-handoff-app/src/billing.ts +7 -0
  101. package/evals/fixtures/tiny-handoff-report-app/README.md +3 -0
  102. package/evals/fixtures/tiny-handoff-report-app/evals/runs/handoff-3/hof-003/with-skill-output.diff +1 -0
  103. package/evals/fixtures/tiny-handoff-report-app/evals/runs/handoff-3/hof-003/with-skill-output.md +1 -0
  104. package/evals/fixtures/tiny-handoff-report-app/evals/scores/hof-003-score.txt +4 -0
  105. package/evals/fixtures/tiny-plan-app/README.md +5 -0
  106. package/evals/fixtures/tiny-plan-app/docs/billing-policy.md +10 -0
  107. package/evals/fixtures/tiny-plan-app/docs/specs/failed-payment-grace-period.md +25 -0
  108. package/evals/fixtures/tiny-plan-app/src/billing.ts +17 -0
  109. package/evals/fixtures/tiny-plan-app/src/settings-page.ts +1 -0
  110. package/evals/fixtures/tiny-plan-app/tests/billing.test.md +8 -0
  111. package/evals/fixtures/tiny-plan-app/tests/settings.test.md +5 -0
  112. package/evals/fixtures/tiny-plan-strict-api-app/README.md +3 -0
  113. package/evals/fixtures/tiny-plan-strict-api-app/docs/billing-policy.md +5 -0
  114. package/evals/fixtures/tiny-plan-strict-api-app/docs/specs/billing-webhook-api.md +25 -0
  115. package/evals/fixtures/tiny-plan-strict-api-app/src/billing.ts +5 -0
  116. package/evals/fixtures/tiny-plan-strict-api-app/src/webhooks.ts +3 -0
  117. package/evals/fixtures/tiny-plan-strict-api-app/tests/billing-webhook.test.md +8 -0
  118. package/evals/fixtures/tiny-post-setup-invalid-config-app/.freeflow/config.json +3 -0
  119. package/evals/fixtures/tiny-post-setup-invalid-config-app/AGENTS.md +15 -0
  120. package/evals/fixtures/tiny-post-setup-invalid-config-app/README.md +16 -0
  121. package/evals/fixtures/tiny-post-setup-invalid-config-app/docs/auth-review.md +15 -0
  122. package/evals/fixtures/tiny-post-setup-invalid-config-app/docs/billing-policy.md +10 -0
  123. package/evals/fixtures/tiny-post-setup-invalid-config-app/docs/copy-conventions.md +15 -0
  124. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/auth-middleware.ts +12 -0
  125. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/billing.ts +20 -0
  126. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/login-copy.ts +1 -0
  127. package/evals/fixtures/tiny-post-setup-invalid-config-app/src/settings-page.ts +1 -0
  128. package/evals/fixtures/tiny-post-setup-invalid-config-app/tests/auth-middleware.test.md +8 -0
  129. package/evals/fixtures/tiny-post-setup-invalid-config-app/tests/billing.test.md +8 -0
  130. package/evals/fixtures/tiny-post-setup-invalid-config-app/tests/copy.test.md +7 -0
  131. package/evals/fixtures/tiny-post-setup-missing-config-app/AGENTS.md +15 -0
  132. package/evals/fixtures/tiny-post-setup-missing-config-app/README.md +16 -0
  133. package/evals/fixtures/tiny-post-setup-missing-config-app/docs/auth-review.md +15 -0
  134. package/evals/fixtures/tiny-post-setup-missing-config-app/docs/billing-policy.md +10 -0
  135. package/evals/fixtures/tiny-post-setup-missing-config-app/docs/copy-conventions.md +15 -0
  136. package/evals/fixtures/tiny-post-setup-missing-config-app/src/auth-middleware.ts +12 -0
  137. package/evals/fixtures/tiny-post-setup-missing-config-app/src/billing.ts +20 -0
  138. package/evals/fixtures/tiny-post-setup-missing-config-app/src/login-copy.ts +1 -0
  139. package/evals/fixtures/tiny-post-setup-missing-config-app/src/settings-page.ts +1 -0
  140. package/evals/fixtures/tiny-post-setup-missing-config-app/tests/auth-middleware.test.md +8 -0
  141. package/evals/fixtures/tiny-post-setup-missing-config-app/tests/billing.test.md +8 -0
  142. package/evals/fixtures/tiny-post-setup-missing-config-app/tests/copy.test.md +7 -0
  143. package/evals/fixtures/tiny-post-setup-source-conflict-app/.freeflow/config.json +3 -0
  144. package/evals/fixtures/tiny-post-setup-source-conflict-app/AGENTS.md +15 -0
  145. package/evals/fixtures/tiny-post-setup-source-conflict-app/README.md +16 -0
  146. package/evals/fixtures/tiny-post-setup-source-conflict-app/docs/auth-review.md +15 -0
  147. package/evals/fixtures/tiny-post-setup-source-conflict-app/docs/billing-policy.md +10 -0
  148. package/evals/fixtures/tiny-post-setup-source-conflict-app/docs/copy-conventions.md +15 -0
  149. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/auth-middleware.ts +12 -0
  150. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/billing.ts +20 -0
  151. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/login-copy.ts +1 -0
  152. package/evals/fixtures/tiny-post-setup-source-conflict-app/src/settings-page.ts +1 -0
  153. package/evals/fixtures/tiny-post-setup-source-conflict-app/tests/auth-middleware.test.md +8 -0
  154. package/evals/fixtures/tiny-post-setup-source-conflict-app/tests/billing.test.md +8 -0
  155. package/evals/fixtures/tiny-post-setup-source-conflict-app/tests/copy.test.md +7 -0
  156. package/evals/fixtures/tiny-report-performance-app/README.md +11 -0
  157. package/evals/fixtures/tiny-report-performance-app/docs/performance.md +10 -0
  158. package/evals/fixtures/tiny-report-performance-app/src/report-summary.ts +29 -0
  159. package/evals/fixtures/tiny-report-performance-app/tests/report-performance.test.md +8 -0
  160. package/evals/fixtures/tiny-review-request-app/README.md +3 -0
  161. package/evals/fixtures/tiny-review-request-app/docs/billing-policy.md +5 -0
  162. package/evals/fixtures/tiny-review-request-app/docs/plans/billing-webhook-api.md +19 -0
  163. package/evals/fixtures/tiny-review-request-app/docs/review/previous-agent-summary.md +20 -0
  164. package/evals/fixtures/tiny-review-request-app/docs/specs/billing-webhook-api.md +25 -0
  165. package/evals/fixtures/tiny-review-request-app/src/billing.ts +11 -0
  166. package/evals/fixtures/tiny-review-request-app/src/webhooks.ts +19 -0
  167. package/evals/fixtures/tiny-review-request-app/tests/billing-webhook.test.md +8 -0
  168. package/evals/fixtures/tiny-review-work-app/README.md +5 -0
  169. package/evals/fixtures/tiny-review-work-app/docs/billing-policy.md +9 -0
  170. package/evals/fixtures/tiny-review-work-app/docs/plans/settings-title-plan.md +12 -0
  171. package/evals/fixtures/tiny-review-work-app/docs/review/previous-agent-summary.md +15 -0
  172. package/evals/fixtures/tiny-review-work-app/docs/specs/settings-title.md +9 -0
  173. package/evals/fixtures/tiny-review-work-app/src/billing.ts +7 -0
  174. package/evals/fixtures/tiny-review-work-app/src/settings-page.ts +1 -0
  175. package/evals/fixtures/tiny-review-work-app/tests/billing.test.md +7 -0
  176. package/evals/fixtures/tiny-review-work-app/tests/settings.test.md +5 -0
  177. package/evals/fixtures/tiny-saas-app/README.md +16 -0
  178. package/evals/fixtures/tiny-saas-app/docs/auth-review.md +15 -0
  179. package/evals/fixtures/tiny-saas-app/docs/billing-policy.md +10 -0
  180. package/evals/fixtures/tiny-saas-app/docs/copy-conventions.md +15 -0
  181. package/evals/fixtures/tiny-saas-app/docs/specs/settings-title.md +13 -0
  182. package/evals/fixtures/tiny-saas-app/src/auth-middleware.ts +12 -0
  183. package/evals/fixtures/tiny-saas-app/src/billing.ts +20 -0
  184. package/evals/fixtures/tiny-saas-app/src/login-copy.ts +1 -0
  185. package/evals/fixtures/tiny-saas-app/src/settings-page.ts +1 -0
  186. package/evals/fixtures/tiny-saas-app/tests/auth-middleware.test.md +8 -0
  187. package/evals/fixtures/tiny-saas-app/tests/billing.test.md +8 -0
  188. package/evals/fixtures/tiny-saas-app/tests/copy.test.md +7 -0
  189. package/evals/fixtures/tiny-setup-agents-app/AGENTS.md +6 -0
  190. package/evals/fixtures/tiny-setup-both-app/AGENTS.md +5 -0
  191. package/evals/fixtures/tiny-setup-both-app/CLAUDE.md +5 -0
  192. package/evals/fixtures/tiny-setup-claude-app/CLAUDE.md +6 -0
  193. package/evals/fixtures/tiny-setup-codex-rules-app/.codex/rules/shell.rules +5 -0
  194. package/evals/fixtures/tiny-setup-codex-rules-app/AGENTS.md +6 -0
  195. package/evals/fixtures/tiny-setup-conflict-app/AGENTS.md +6 -0
  196. package/evals/fixtures/tiny-setup-existing-block-app/AGENTS.md +14 -0
  197. package/evals/fixtures/tiny-setup-four-rules-app/CLAUDE.md +6 -0
  198. package/evals/fixtures/tiny-skill-dev-app/README.md +10 -0
  199. package/evals/fixtures/tiny-skill-dev-app/evals/prompts/review-pr-001.txt +8 -0
  200. package/evals/fixtures/tiny-skill-dev-app/evals/reports/review-pr-failure.md +17 -0
  201. package/evals/fixtures/tiny-skill-dev-app/skills/review-pr/SKILL.md +13 -0
  202. package/evals/fixtures/tiny-team-app/README.md +5 -0
  203. package/evals/fixtures/tiny-team-app/docs/product.md +6 -0
  204. package/evals/fixtures/tiny-team-app/src/teams.ts +9 -0
  205. package/evals/fixtures/tiny-team-app/src/users.ts +5 -0
  206. package/evals/fixtures/tiny-team-app/tests/teams.test.md +7 -0
  207. package/evals/fixtures/tiny-verify-app/README.md +5 -0
  208. package/evals/fixtures/tiny-verify-app/src/settings-nav.ts +1 -0
  209. package/evals/fixtures/tiny-verify-app/src/settings-page.ts +1 -0
  210. package/evals/fixtures/tiny-verify-app/tests/settings.test.md +7 -0
  211. package/evals/prompts/aon-001.txt +2 -0
  212. package/evals/prompts/byp-001.txt +2 -0
  213. package/evals/prompts/byp-002.txt +2 -0
  214. package/evals/prompts/cap-001.txt +3 -0
  215. package/evals/prompts/cap-002.txt +3 -0
  216. package/evals/prompts/cmd-001.txt +3 -0
  217. package/evals/prompts/cmd-002.txt +3 -0
  218. package/evals/prompts/cmd-003.txt +6 -0
  219. package/evals/prompts/cmd-004.txt +5 -0
  220. package/evals/prompts/cmd-005.txt +5 -0
  221. package/evals/prompts/cmd-006.txt +5 -0
  222. package/evals/prompts/cmd-007.txt +5 -0
  223. package/evals/prompts/cmd-008.txt +5 -0
  224. package/evals/prompts/cmd-009.txt +8 -0
  225. package/evals/prompts/cmd-010.txt +5 -0
  226. package/evals/prompts/cmd-011.txt +5 -0
  227. package/evals/prompts/cmd-012.txt +5 -0
  228. package/evals/prompts/cmd-013.txt +5 -0
  229. package/evals/prompts/cmd-014.txt +7 -0
  230. package/evals/prompts/cmd-015.txt +7 -0
  231. package/evals/prompts/cmd-016.txt +5 -0
  232. package/evals/prompts/cmt-001.txt +1 -0
  233. package/evals/prompts/cmt-002.txt +1 -0
  234. package/evals/prompts/cmt-003.txt +1 -0
  235. package/evals/prompts/cmt-004.txt +1 -0
  236. package/evals/prompts/cmt-005.txt +1 -0
  237. package/evals/prompts/dfd-001.txt +3 -0
  238. package/evals/prompts/dia-001.txt +3 -0
  239. package/evals/prompts/dia-002.txt +3 -0
  240. package/evals/prompts/dia-003.txt +3 -0
  241. package/evals/prompts/dis-001.txt +5 -0
  242. package/evals/prompts/dis-002.txt +5 -0
  243. package/evals/prompts/esk-001.txt +5 -0
  244. package/evals/prompts/esk-002.txt +5 -0
  245. package/evals/prompts/esk-003.txt +5 -0
  246. package/evals/prompts/grc-001.txt +3 -0
  247. package/evals/prompts/hof-001.txt +3 -0
  248. package/evals/prompts/hof-002.txt +1 -0
  249. package/evals/prompts/hof-003.txt +1 -0
  250. package/evals/prompts/hof-004.txt +1 -0
  251. package/evals/prompts/hof-005.txt +1 -0
  252. package/evals/prompts/ivg-001.txt +1 -0
  253. package/evals/prompts/ivg-002.txt +11 -0
  254. package/evals/prompts/ivg-003.txt +1 -0
  255. package/evals/prompts/ivg-004.txt +1 -0
  256. package/evals/prompts/mode-001.txt +3 -0
  257. package/evals/prompts/mode-002.txt +1 -0
  258. package/evals/prompts/mode-003.txt +3 -0
  259. package/evals/prompts/mode-004.txt +3 -0
  260. package/evals/prompts/mode-005.txt +3 -0
  261. package/evals/prompts/mode-006.txt +3 -0
  262. package/evals/prompts/mode-007.txt +3 -0
  263. package/evals/prompts/otr-001.txt +3 -0
  264. package/evals/prompts/otr-002.txt +3 -0
  265. package/evals/prompts/rar-001.txt +5 -0
  266. package/evals/prompts/rar-002.txt +3 -0
  267. package/evals/prompts/rar-003.txt +6 -0
  268. package/evals/prompts/rar-004.txt +15 -0
  269. package/evals/prompts/rar-005.txt +10 -0
  270. package/evals/prompts/rbr-001.txt +3 -0
  271. package/evals/prompts/rbr-002.txt +3 -0
  272. package/evals/prompts/rbr-003.txt +7 -0
  273. package/evals/prompts/rev-001.txt +3 -0
  274. package/evals/prompts/rev-002.txt +5 -0
  275. package/evals/prompts/rev-003.txt +6 -0
  276. package/evals/prompts/rev-004.txt +1 -0
  277. package/evals/prompts/rev-005.txt +15 -0
  278. package/evals/prompts/rev-006.txt +5 -0
  279. package/evals/prompts/stp-001.txt +1 -0
  280. package/evals/prompts/stp-002.txt +1 -0
  281. package/evals/prompts/stp-003.txt +1 -0
  282. package/evals/prompts/stp-004.txt +1 -0
  283. package/evals/prompts/stp-005.txt +1 -0
  284. package/evals/prompts/stp-006.txt +1 -0
  285. package/evals/prompts/stp-007.txt +1 -0
  286. package/evals/prompts/stp-008.txt +1 -0
  287. package/evals/prompts/stp-009.txt +1 -0
  288. package/evals/prompts/stp-010.txt +1 -0
  289. package/evals/prompts/stp-011.txt +1 -0
  290. package/evals/prompts/vfy-003.txt +1 -0
  291. package/evals/prompts/wpl-001.txt +3 -0
  292. package/evals/prompts/wpl-002.txt +5 -0
  293. package/evals/prompts/wpl-003.txt +3 -0
  294. package/evals/prompts/wpl-004.txt +5 -0
  295. package/evals/prompts/wpl-005.txt +1 -0
  296. package/evals/prompts/wrc-001.txt +10 -0
  297. package/evals/prompts/wrc-002.txt +3 -0
  298. package/evals/prompts/wsk-001.txt +6 -0
  299. package/evals/prompts/wsp-001.txt +5 -0
  300. package/evals/prompts/wsp-002.txt +15 -0
  301. package/evals/prompts/wsp-003.txt +3 -0
  302. package/evals/prompts/wsp-004.txt +15 -0
  303. package/evals/prompts/wsp-005.txt +5 -0
  304. package/evals/prompts/wsp-006.txt +12 -0
  305. package/evals/prompts/wsp-007.txt +9 -0
  306. package/evals/prompts/wsp-008.txt +13 -0
  307. package/evals/prompts/xpl-001.txt +1 -0
  308. package/evals/prompts/xpl-002.txt +3 -0
  309. package/evals/prompts/xpl-003.txt +3 -0
  310. package/evals/prompts/xpl-004.txt +3 -0
  311. package/evals/prompts/xpl-005.txt +5 -0
  312. package/evals/prompts/xpl-006.txt +3 -0
  313. package/evals/registries/adversarial-evals.json +39 -0
  314. package/evals/registries/fixture-evals.json +2513 -0
  315. package/evals/registries/handoff-evals.json +74 -0
  316. package/evals/registries/legacy-evals.json +147 -0
  317. package/evals/registries/skill-evidence.json +193 -0
  318. package/evals/registries/verify-work-evals.json +46 -0
  319. package/evals/reports/acceptance/v0.1-acceptance-report.md +130 -0
  320. package/evals/reports/by-command-surface/command-surface-1-report.md +45 -0
  321. package/evals/reports/by-command-surface/command-surface-10-report.md +76 -0
  322. package/evals/reports/by-command-surface/command-surface-11-report.md +77 -0
  323. package/evals/reports/by-command-surface/command-surface-12-report.md +91 -0
  324. package/evals/reports/by-command-surface/command-surface-13-report.md +64 -0
  325. package/evals/reports/by-command-surface/command-surface-14-report.md +66 -0
  326. package/evals/reports/by-command-surface/command-surface-15-report.md +124 -0
  327. package/evals/reports/by-command-surface/command-surface-16-report.md +39 -0
  328. package/evals/reports/by-command-surface/command-surface-2-report.md +80 -0
  329. package/evals/reports/by-command-surface/command-surface-3-report.md +86 -0
  330. package/evals/reports/by-command-surface/command-surface-4-report.md +76 -0
  331. package/evals/reports/by-command-surface/command-surface-5-report.md +80 -0
  332. package/evals/reports/by-command-surface/command-surface-6-report.md +74 -0
  333. package/evals/reports/by-command-surface/command-surface-7-report.md +84 -0
  334. package/evals/reports/by-command-surface/command-surface-8-report.md +79 -0
  335. package/evals/reports/by-command-surface/command-surface-9-report.md +79 -0
  336. package/evals/reports/by-command-surface/command-surface-matrix.md +91 -0
  337. package/evals/reports/by-skill/bypass-1-report.md +124 -0
  338. package/evals/reports/by-skill/capture-decisions-1-report.md +99 -0
  339. package/evals/reports/by-skill/capture-decisions-2-report.md +102 -0
  340. package/evals/reports/by-skill/commit-work-1-report.md +165 -0
  341. package/evals/reports/by-skill/commit-work-2-report.md +109 -0
  342. package/evals/reports/by-skill/design-for-depth-1-report.md +95 -0
  343. package/evals/reports/by-skill/diagnose-failure-1-report.md +91 -0
  344. package/evals/reports/by-skill/diagnose-failure-2-report.md +94 -0
  345. package/evals/reports/by-skill/discover-1-report.md +118 -0
  346. package/evals/reports/by-skill/evaluate-skill-2-report.md +71 -0
  347. package/evals/reports/by-skill/execute-plan-1-report.md +103 -0
  348. package/evals/reports/by-skill/execute-plan-2-report.md +112 -0
  349. package/evals/reports/by-skill/execute-plan-3-report.md +87 -0
  350. package/evals/reports/by-skill/grill-context-1-report.md +103 -0
  351. package/evals/reports/by-skill/handoff-1-report.md +123 -0
  352. package/evals/reports/by-skill/handoff-2-report.md +105 -0
  353. package/evals/reports/by-skill/handoff-3-report.md +100 -0
  354. package/evals/reports/by-skill/handoff-7-report.md +77 -0
  355. package/evals/reports/by-skill/interview-gate-1-report.md +63 -0
  356. package/evals/reports/by-skill/interview-gate-2-report.md +105 -0
  357. package/evals/reports/by-skill/mode-contract-1-report.md +74 -0
  358. package/evals/reports/by-skill/mode-contract-2-report.md +87 -0
  359. package/evals/reports/by-skill/mode-contract-3-report.md +65 -0
  360. package/evals/reports/by-skill/mode-contract-4-report.md +71 -0
  361. package/evals/reports/by-skill/mode-contract-5-report.md +70 -0
  362. package/evals/reports/by-skill/output-router-1-report.md +76 -0
  363. package/evals/reports/by-skill/output-router-2-report.md +65 -0
  364. package/evals/reports/by-skill/research-1-report.md +144 -0
  365. package/evals/reports/by-skill/research-brief-1-report.md +94 -0
  366. package/evals/reports/by-skill/research-brief-2-report.md +75 -0
  367. package/evals/reports/by-skill/review-artifact-1-report.md +91 -0
  368. package/evals/reports/by-skill/review-artifact-2-report.md +79 -0
  369. package/evals/reports/by-skill/review-artifact-3-report.md +120 -0
  370. package/evals/reports/by-skill/review-artifact-4-report.md +89 -0
  371. package/evals/reports/by-skill/review-artifact-5-report.md +66 -0
  372. package/evals/reports/by-skill/review-work-1-report.md +85 -0
  373. package/evals/reports/by-skill/review-work-2-report.md +87 -0
  374. package/evals/reports/by-skill/review-work-3-report.md +104 -0
  375. package/evals/reports/by-skill/review-work-4-report.md +108 -0
  376. package/evals/reports/by-skill/review-work-5-report.md +73 -0
  377. package/evals/reports/by-skill/review-work-6-report.md +66 -0
  378. package/evals/reports/by-skill/setup-freeflow-1-report.md +199 -0
  379. package/evals/reports/by-skill/setup-freeflow-2-report.md +105 -0
  380. package/evals/reports/by-skill/setup-freeflow-3-report.md +105 -0
  381. package/evals/reports/by-skill/setup-freeflow-4-report.md +88 -0
  382. package/evals/reports/by-skill/setup-freeflow-5-report.md +115 -0
  383. package/evals/reports/by-skill/skill-authoring-1-report.md +81 -0
  384. package/evals/reports/by-skill/verify-work-1-report.md +111 -0
  385. package/evals/reports/by-skill/verify-work-2-report.md +120 -0
  386. package/evals/reports/by-skill/workflow-1-report.md +65 -0
  387. package/evals/reports/by-skill/write-plan-1-report.md +123 -0
  388. package/evals/reports/by-skill/write-plan-2-report.md +98 -0
  389. package/evals/reports/by-skill/write-plan-3-report.md +110 -0
  390. package/evals/reports/by-skill/write-spec-1-report.md +88 -0
  391. package/evals/reports/by-skill/write-spec-2-report.md +89 -0
  392. package/evals/reports/by-skill/write-spec-3-report.md +90 -0
  393. package/evals/reports/by-skill/write-spec-4-report.md +167 -0
  394. package/evals/reports/harness/claude-harness-1-report.md +103 -0
  395. package/evals/reports/harness/eval-harness-1-report.md +91 -0
  396. package/evals/reports/iterations/iteration-1-report.md +71 -0
  397. package/evals/reports/iterations/iteration-2-report.md +78 -0
  398. package/evals/reports/iterations/iteration-3-report.md +118 -0
  399. package/evals/reports/iterations/iteration-4-report.md +131 -0
  400. package/evals/reports/iterations/iteration-5-report.md +149 -0
  401. package/evals/reports/iterations/iteration-6-report.md +136 -0
  402. package/evals/reports/runtime/always-on-runtime-1-report.md +107 -0
  403. package/evals/reports/runtime/context-mode-normalized-benchmark-1-report.md +52 -0
  404. package/evals/reports/runtime/context-mode-real-deep-baseline-1-report.md +410 -0
  405. package/evals/reports/runtime/context-mode-real-deep-final-slice-11-report.md +203 -0
  406. package/evals/reports/runtime/context-mode-real-deep-final-slice-11-review.md +51 -0
  407. package/evals/reports/runtime/context-saving-native-tools-baseline-1-report.md +99 -0
  408. package/evals/reports/runtime/eryx-python-compatibility-reprobe-1-report.md +166 -0
  409. package/evals/reports/runtime/eryx-python-proof-spike-1-report.md +96 -0
  410. package/evals/reports/runtime/eryx-python-proof-spike-2-report.md +151 -0
  411. package/evals/reports/runtime/eryx-python-script-derive-execution-1-report.md +233 -0
  412. package/evals/reports/runtime/jq-script-derive-execution-1-report.md +215 -0
  413. package/evals/reports/runtime/jq-wasm-proof-spike-1-report.md +67 -0
  414. package/evals/reports/runtime/output-router-benchmark-1-report.md +81 -0
  415. package/evals/reports/runtime/output-router-capture-derive-provider-eval-1-report.md +35 -0
  416. package/evals/reports/runtime/output-router-codex-large-index-sqlite-adhoc-report.md +150 -0
  417. package/evals/reports/runtime/output-router-codex-qa-benchmark-1-report.md +46 -0
  418. package/evals/reports/runtime/output-router-command-benchmark-1-report.md +62 -0
  419. package/evals/reports/runtime/output-router-index-benchmark-1-report.md +64 -0
  420. package/evals/reports/runtime/output-router-regression-1-report.md +81 -0
  421. package/evals/reports/runtime/output-router-transform-eval-1-report.md +28 -0
  422. package/evals/reports/runtime/pi-observed-routing-eval-1-report.md +44 -0
  423. package/evals/reports/runtime/quickjs-script-derive-execution-1-report.md +159 -0
  424. package/evals/reports/runtime/quickjs-wasi-proof-spike-1-report.md +55 -0
  425. package/evals/reports/runtime/render-format-row-protocol-1-report.md +58 -0
  426. package/evals/reports/runtime/script-sandbox-adapter-selection-review-1-report.md +84 -0
  427. package/evals/reports/runtime/script-sandbox-probe-resource-hardening-1-report.md +51 -0
  428. package/evals/reports/runtime/storage-policy-benchmark-1-report.md +176 -0
  429. package/evals/reports/runtime/vault-index-storage-spike-1-report.md +39 -0
  430. package/evals/reports/runtime/workflow-context-hook-1-report.md +82 -0
  431. package/evals/runbooks/adversarial-eval-runbook.md +28 -0
  432. package/evals/runbooks/fixture-eval-runbook.md +137 -0
  433. package/evals/runbooks/handoff-eval-runbook.md +22 -0
  434. package/evals/runbooks/verify-work-eval-runbook.md +27 -0
  435. package/evals/scripts/audit-command-surface.sh +160 -0
  436. package/evals/scripts/check-activation-contract.sh +121 -0
  437. package/evals/scripts/check-runtime-context-hook.sh +183 -0
  438. package/evals/scripts/grade-fixture-eval.sh +446 -0
  439. package/evals/scripts/run-claude-fixture-eval.sh +26 -0
  440. package/evals/scripts/run-codex-fixture-eval.sh +26 -0
  441. package/evals/scripts/run-eryx-python-proof-spike.js +559 -0
  442. package/evals/scripts/run-fixture-eval-by-id.sh +23 -0
  443. package/evals/scripts/run-fixture-eval.sh +464 -0
  444. package/evals/scripts/run-jq-wasm-proof-spike.js +299 -0
  445. package/evals/scripts/run-output-router-transform-eval.js +115 -0
  446. package/evals/scripts/run-pi-observed-routing-eval.js +478 -0
  447. package/evals/scripts/run-quickjs-wasi-proof-spike.js +339 -0
  448. package/evals/scripts/skill-evidence.sh +316 -0
  449. package/evals/scripts/validate-release-metadata.sh +486 -0
  450. package/evals/suites/v0.1-acceptance-suite.md +131 -0
  451. package/{plugins/freeflow/hooks → hooks}/freeflow-runtime-context.mjs +46 -12
  452. package/package.json +39 -19
  453. package/pi-extension/dist/host-producer-identification.js +186 -0
  454. package/pi-extension/dist/index.js +85 -0
  455. package/pi-extension/dist/mcp-config.js +30 -0
  456. package/pi-extension/dist/native-safety-net.js +209 -0
  457. package/pi-extension/dist/observed-tool-routing.js +114 -0
  458. package/pi-extension/dist/renderers.js +835 -0
  459. package/pi-extension/dist/router-tools.js +438 -0
  460. package/pi-extension/dist/runtime-context.js +288 -0
  461. package/pi-extension/dist/schemas.js +254 -0
  462. package/pi-extension/dist/status.js +449 -0
  463. package/pi-extension/dist/utils.js +467 -0
  464. package/pi-extension/src/host-producer-identification.ts +226 -0
  465. package/pi-extension/src/index.ts +121 -0
  466. package/pi-extension/src/mcp-config.ts +32 -0
  467. package/pi-extension/src/native-safety-net.ts +252 -0
  468. package/pi-extension/src/observed-tool-routing.ts +126 -0
  469. package/pi-extension/src/renderers.ts +917 -0
  470. package/pi-extension/src/router-tools.ts +478 -0
  471. package/pi-extension/src/runtime-context.ts +347 -0
  472. package/pi-extension/src/schemas.ts +259 -0
  473. package/pi-extension/src/status.ts +505 -0
  474. package/pi-extension/src/utils.ts +492 -0
  475. package/pi-extension/tsconfig.json +16 -0
  476. package/{plugins/freeflow/docs → plugin-docs}/README.md +3 -3
  477. package/plugin-docs/adr/0002-evals-before-hooks.md +17 -0
  478. package/{plugins/freeflow/docs → plugin-docs}/adr/0003-release-boundary.md +2 -2
  479. package/plugin-docs/adr/0004-discover-replaces-shallow-discovery-skills.md +26 -0
  480. package/plugin-docs/adr/README.md +10 -0
  481. package/plugin-docs/architecture.md +89 -0
  482. package/plugin-docs/output-router.md +396 -0
  483. package/plugin-docs/release-evidence.md +77 -0
  484. package/{plugins/freeflow/docs → plugin-docs}/skills.md +3 -2
  485. package/{plugins/freeflow/docs → plugin-docs}/workflow.md +4 -4
  486. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/benchmark-harness.js +1 -1
  487. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/benchmarks.js +14 -14
  488. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/codex-qa-benchmarks.js +6 -6
  489. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/command-benchmarks.d.ts +1 -1
  490. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/command-benchmarks.js +11 -10
  491. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +74 -0
  492. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +707 -0
  493. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +124 -0
  494. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +1295 -0
  495. package/router/dist/benchmarks/context-saving-baseline.d.ts +54 -0
  496. package/router/dist/benchmarks/context-saving-baseline.js +439 -0
  497. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/index-benchmarks.d.ts +16 -2
  498. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/index-benchmarks.js +330 -26
  499. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +90 -0
  500. package/router/dist/benchmarks/storage-policy-benchmarks.js +538 -0
  501. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +47 -0
  502. package/router/dist/benchmarks/vault-index-benchmarks.js +257 -0
  503. package/router/dist/config/config.d.ts +96 -0
  504. package/router/dist/config/config.js +453 -0
  505. package/{plugins/freeflow/router/dist → router/dist/config}/schema.js +248 -2
  506. package/router/dist/config/types.d.ts +521 -0
  507. package/router/dist/config/types.js +30 -0
  508. package/{plugins/freeflow/router/dist → router/dist/evidence}/bounded-evidence.d.ts +1 -1
  509. package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence-range-selector.js +65 -14
  510. package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence-search.js +18 -2
  511. package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence.d.ts +1 -1
  512. package/router/dist/evidence/failure-contracts.d.ts +27 -0
  513. package/router/dist/evidence/failure-contracts.js +160 -0
  514. package/router/dist/index.d.ts +30 -0
  515. package/router/dist/index.js +32 -0
  516. package/router/dist/processing/engine.d.ts +108 -0
  517. package/router/dist/processing/engine.js +435 -0
  518. package/router/dist/processing/reducers.d.ts +266 -0
  519. package/router/dist/processing/reducers.js +1495 -0
  520. package/router/dist/processing/renderers.d.ts +25 -0
  521. package/router/dist/processing/renderers.js +186 -0
  522. package/router/dist/processing/scripts.d.ts +78 -0
  523. package/router/dist/processing/scripts.js +333 -0
  524. package/router/dist/routing/observed-reducers.d.ts +35 -0
  525. package/router/dist/routing/observed-reducers.js +647 -0
  526. package/router/dist/routing/observed-routing.d.ts +17 -0
  527. package/router/dist/routing/observed-routing.js +377 -0
  528. package/{plugins/freeflow/router/dist → router/dist/routing}/parsers.d.ts +1 -1
  529. package/{plugins/freeflow/router/dist → router/dist/routing}/parsers.js +1 -1
  530. package/router/dist/routing/run-filters.d.ts +56 -0
  531. package/router/dist/routing/run-filters.js +230 -0
  532. package/router/dist/routing/run-reducers.d.ts +30 -0
  533. package/router/dist/routing/run-reducers.js +110 -0
  534. package/router/dist/sandbox/adapter-roots.d.ts +38 -0
  535. package/router/dist/sandbox/adapter-roots.js +64 -0
  536. package/router/dist/sandbox/eryx-python-adapter.d.ts +9 -0
  537. package/router/dist/sandbox/eryx-python-adapter.js +797 -0
  538. package/router/dist/sandbox/jq-wasm-adapter.d.ts +9 -0
  539. package/router/dist/sandbox/jq-wasm-adapter.js +421 -0
  540. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +9 -0
  541. package/router/dist/sandbox/quickjs-wasi-adapter.js +381 -0
  542. package/router/dist/sandbox/script-sandbox.d.ts +113 -0
  543. package/router/dist/sandbox/script-sandbox.js +303 -0
  544. package/router/dist/setup/script-transform-adapters.d.ts +28 -0
  545. package/router/dist/setup/script-transform-adapters.js +259 -0
  546. package/router/dist/tools/batch.d.ts +22 -0
  547. package/router/dist/tools/batch.js +509 -0
  548. package/router/dist/tools/run.d.ts +50 -0
  549. package/router/dist/tools/run.js +1219 -0
  550. package/router/dist/tools/search.d.ts +44 -0
  551. package/{plugins/freeflow/router/dist/retrieve.js → router/dist/tools/search.js} +395 -45
  552. package/router/dist/transform/engine.d.ts +143 -0
  553. package/router/dist/transform/engine.js +1955 -0
  554. package/router/dist/vault/vault-index.d.ts +106 -0
  555. package/router/dist/vault/vault-index.js +411 -0
  556. package/{plugins/freeflow/router/dist → router/dist/vault}/vault.d.ts +24 -1
  557. package/{plugins/freeflow/router/dist → router/dist/vault}/vault.js +152 -1
  558. package/skills/design-for-depth/SKILL.md +90 -0
  559. package/skills/design-for-depth/references/design-pressure-signals.md +265 -0
  560. package/skills/design-for-depth/references/software-design-philosophy.md +219 -0
  561. package/{plugins/freeflow/skills → skills}/diagnose-failure/SKILL.md +6 -1
  562. package/{plugins/freeflow/skills/research → skills/discover}/ARTIFACT-DESTINATIONS.md +4 -4
  563. package/{plugins/freeflow/skills/research → skills/discover}/CHECKPOINTS.md +4 -4
  564. package/skills/discover/SKILL.md +173 -0
  565. package/{plugins/freeflow/skills → skills}/execute-plan/SKILL.md +5 -4
  566. package/{plugins/freeflow/skills → skills}/execute-plan/references/execution-map.md +2 -2
  567. package/{plugins/freeflow/skills → skills}/mode-contract/SKILL.md +9 -4
  568. package/skills/output-router/SKILL.md +202 -0
  569. package/skills/output-router/references/safety-policy.md +40 -0
  570. package/{plugins/freeflow/skills → skills}/review-artifact/SKILL.md +5 -2
  571. package/{plugins/freeflow/skills → skills}/review-artifact/references/reviewer-prompt.md +2 -1
  572. package/{plugins/freeflow/skills → skills}/review-work/SKILL.md +6 -1
  573. package/{plugins/freeflow/skills → skills}/setup-freeflow/SKILL.md +21 -9
  574. package/{plugins/freeflow/skills → skills}/setup-freeflow/references/activation-contract.md +11 -10
  575. package/{plugins/freeflow/skills → skills}/setup-freeflow/references/host-setup.md +3 -3
  576. package/skills/setup-freeflow/references/output-router-setup.md +102 -0
  577. package/{plugins/freeflow/skills → skills}/verify-work/SKILL.md +3 -1
  578. package/{plugins/freeflow/skills → skills}/workflow/SKILL.md +16 -14
  579. package/{plugins/freeflow/skills → skills}/workflow/references/workflow-map.md +16 -14
  580. package/{plugins/freeflow/skills → skills}/write-plan/SKILL.md +9 -1
  581. package/{plugins/freeflow/skills → skills}/write-spec/SKILL.md +9 -6
  582. package/plugins/freeflow/docs/adr/0002-evals-before-hooks.md +0 -17
  583. package/plugins/freeflow/docs/adr/0004-research-replaces-shallow-discovery-skills.md +0 -26
  584. package/plugins/freeflow/docs/adr/README.md +0 -8
  585. package/plugins/freeflow/docs/architecture.md +0 -86
  586. package/plugins/freeflow/docs/output-router.md +0 -212
  587. package/plugins/freeflow/docs/release-evidence.md +0 -69
  588. package/plugins/freeflow/pi-extension/index.js +0 -1176
  589. package/plugins/freeflow/router/dist/config.d.ts +0 -22
  590. package/plugins/freeflow/router/dist/config.js +0 -114
  591. package/plugins/freeflow/router/dist/experimental-local-index.d.ts +0 -1
  592. package/plugins/freeflow/router/dist/experimental-local-index.js +0 -1
  593. package/plugins/freeflow/router/dist/index.d.ts +0 -12
  594. package/plugins/freeflow/router/dist/index.js +0 -12
  595. package/plugins/freeflow/router/dist/retrieve.d.ts +0 -33
  596. package/plugins/freeflow/router/dist/run.d.ts +0 -26
  597. package/plugins/freeflow/router/dist/run.js +0 -356
  598. package/plugins/freeflow/router/dist/types.d.ts +0 -234
  599. package/plugins/freeflow/router/dist/types.js +0 -9
  600. package/plugins/freeflow/skills/output-router/SKILL.md +0 -69
  601. package/plugins/freeflow/skills/output-router/references/safety-policy.md +0 -33
  602. package/plugins/freeflow/skills/research/LANGUAGE.md +0 -61
  603. package/plugins/freeflow/skills/research/SKILL.md +0 -128
  604. package/plugins/freeflow/skills/setup-freeflow/references/output-router-setup.md +0 -52
  605. /package/{plugins/freeflow/assets → assets}/freeflow-plugin-icon-transparent.png +0 -0
  606. /package/{plugins/freeflow/hooks → hooks}/hooks.json +0 -0
  607. /package/{plugins/freeflow/docs → plugin-docs}/adr/0001-three-modes.md +0 -0
  608. /package/{plugins/freeflow/router/dist → router/dist/benchmarks}/benchmark-harness.d.ts +0 -0
  609. /package/{plugins/freeflow/router/dist → router/dist/benchmarks}/benchmarks.d.ts +0 -0
  610. /package/{plugins/freeflow/router/dist → router/dist/benchmarks}/codex-qa-benchmarks.d.ts +0 -0
  611. /package/{plugins/freeflow/router/dist → router/dist/config}/router-contract.d.ts +0 -0
  612. /package/{plugins/freeflow/router/dist → router/dist/config}/router-contract.js +0 -0
  613. /package/{plugins/freeflow/router/dist → router/dist/config}/schema.d.ts +0 -0
  614. /package/{plugins/freeflow/router/dist → router/dist/evidence}/bounded-evidence.js +0 -0
  615. /package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence-range-selector.d.ts +0 -0
  616. /package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence-search.d.ts +0 -0
  617. /package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence.js +0 -0
  618. /package/{plugins/freeflow/router/dist → router/dist/evidence}/line-ranges.d.ts +0 -0
  619. /package/{plugins/freeflow/router/dist → router/dist/evidence}/line-ranges.js +0 -0
  620. /package/{plugins/freeflow/router → router}/dist/experiments/local-index.d.ts +0 -0
  621. /package/{plugins/freeflow/router → router}/dist/experiments/local-index.js +0 -0
  622. /package/{plugins/freeflow/router/dist → router/dist/repo}/repo-traversal.d.ts +0 -0
  623. /package/{plugins/freeflow/router/dist → router/dist/repo}/repo-traversal.js +0 -0
  624. /package/{plugins/freeflow/skills → skills}/bypass/SKILL.md +0 -0
  625. /package/{plugins/freeflow/skills → skills}/commit-work/SKILL.md +0 -0
  626. /package/{plugins/freeflow/skills → skills}/commit-work/references/staging-decisions.md +0 -0
  627. /package/{plugins/freeflow/skills → skills}/diagnose-failure/references/feedback-loop-catalog.md +0 -0
  628. /package/{plugins/freeflow/skills → skills}/diagnose-failure/references/flaky-and-performance.md +0 -0
  629. /package/{plugins/freeflow/skills → skills}/evaluate-skill/SKILL.md +0 -0
  630. /package/{plugins/freeflow/skills → skills}/evaluate-skill/references/eval-patterns.md +0 -0
  631. /package/{plugins/freeflow/skills → skills}/evaluate-skill/references/grading-priority.md +0 -0
  632. /package/{plugins/freeflow/skills → skills}/handoff/SKILL.md +0 -0
  633. /package/{plugins/freeflow/skills → skills}/handoff/references/templates.md +0 -0
  634. /package/{plugins/freeflow/skills → skills}/interview-gate/SKILL.md +0 -0
  635. /package/{plugins/freeflow/skills → skills}/review-work/references/reviewer-prompt.md +0 -0
  636. /package/{plugins/freeflow/skills → skills}/write-plan/references/plan-shapes.md +0 -0
  637. /package/{plugins/freeflow/skills → skills}/write-skill/SKILL.md +0 -0
  638. /package/{plugins/freeflow/skills → skills}/write-spec/references/artifact-standards.md +0 -0
  639. /package/{plugins/freeflow/skills → skills}/write-spec/references/spec-shapes.md +0 -0
@@ -0,0 +1,1495 @@
1
+ const TEST_OUTPUT_REDUCER = {
2
+ name: "test-output",
3
+ version: "1",
4
+ };
5
+ const BUILD_OUTPUT_REDUCER = {
6
+ name: "build-output",
7
+ version: "1",
8
+ };
9
+ const DIAGNOSTICS_REDUCER = {
10
+ name: "diagnostics",
11
+ version: "1",
12
+ };
13
+ const MCP_TOOLS_REDUCER = {
14
+ name: "mcp-tools",
15
+ version: "1",
16
+ };
17
+ const JSON_QUERY_REDUCER = {
18
+ name: "json-query",
19
+ version: "1",
20
+ };
21
+ const TABLE_REDUCER = {
22
+ name: "table",
23
+ version: "1",
24
+ };
25
+ const BROWSER_SNAPSHOT_REDUCER = {
26
+ name: "browser-snapshot",
27
+ version: "1",
28
+ };
29
+ const GIT_LOG_REDUCER = {
30
+ name: "git-log",
31
+ version: "1",
32
+ };
33
+ const ACCESS_LOG_REDUCER = {
34
+ name: "access-log",
35
+ version: "1",
36
+ };
37
+ const MIN_ACCESS_LOG_LINES = 5;
38
+ const MIN_ACCESS_LOG_CONFIDENCE = 0.8;
39
+ const SLOW_REQUEST_THRESHOLD_MS = 1_000;
40
+ const ACCESS_LOG_LINE = /^(\S+)\s+\S+\s+\S+\s+\[[^\]]+\]\s+"([A-Z]+)\s+([^"\s]+)\s+HTTP\/[^"\s]+"\s+(\d{3})\s+(?:\d+|-)\s+(\d+)ms\s*$/;
41
+ export function selectProcessingReducer(input) {
42
+ const testOutput = reduceTestOutput(input.text);
43
+ const buildOutput = reduceBuildOutput(input.text);
44
+ const diagnostics = reduceDiagnosticsOutput(input.text);
45
+ const mcpTools = reduceMcpToolsOutput(input.text);
46
+ const jsonQuery = reduceJsonQueryOutput(input.text, input.goal);
47
+ const table = reduceTableOutput(input.text);
48
+ const browserSnapshot = reduceBrowserSnapshotOutput(input.text);
49
+ const gitLog = reduceGitLogOutput(input.text);
50
+ const accessLog = reduceAccessLog(input.text);
51
+ const candidates = [testOutput.candidate, buildOutput.candidate, diagnostics.candidate, mcpTools.candidate, jsonQuery.candidate, table.candidate, browserSnapshot.candidate, gitLog.candidate, accessLog.candidate];
52
+ const selected = [testOutput, buildOutput, diagnostics, mcpTools, jsonQuery, table, browserSnapshot, gitLog, accessLog].find((reduced) => reduced.result !== undefined);
53
+ if (selected?.result) {
54
+ return {
55
+ status: "selected",
56
+ candidates,
57
+ selected: selected.candidate,
58
+ result: selected.result,
59
+ reason: selected.candidate.reason,
60
+ };
61
+ }
62
+ return {
63
+ status: "not_selected",
64
+ candidates,
65
+ reason: "No high-confidence built-in reducer matched the loaded source.",
66
+ };
67
+ }
68
+ export function reduceTestOutput(text) {
69
+ const lines = text.split(/\r?\n/);
70
+ const testFiles = findTestCounts(lines, "Test Files");
71
+ const tests = findTestCounts(lines, "Tests");
72
+ const failedFiles = uniqueStrings(lines.map(parseFailedTestFile).filter((file) => file !== undefined));
73
+ const failedTests = lines.map(parseFailedTestName).filter((name) => name !== undefined).slice(0, 8);
74
+ const confidence = testOutputConfidence({ testFiles, tests, failedFiles, failedTests, text });
75
+ const candidate = {
76
+ ...TEST_OUTPUT_REDUCER,
77
+ confidence,
78
+ reason: `Detected test summary counts=${testFiles || tests ? "yes" : "no"}, failedFiles=${failedFiles.length}, failedTests=${failedTests.length}.`,
79
+ };
80
+ if (confidence < 0.8 || (testFiles === undefined && tests === undefined)) {
81
+ return { candidate };
82
+ }
83
+ const details = {
84
+ kind: "test-output",
85
+ testFiles: testFiles ?? {},
86
+ tests: tests ?? {},
87
+ failedFiles,
88
+ failedTests,
89
+ };
90
+ return {
91
+ candidate,
92
+ result: {
93
+ ...TEST_OUTPUT_REDUCER,
94
+ confidence,
95
+ reason: candidate.reason,
96
+ facts: testOutputFacts(details),
97
+ visibleText: renderTestOutputSummary(details),
98
+ details,
99
+ },
100
+ };
101
+ }
102
+ function findTestCounts(lines, label) {
103
+ const pattern = label === "Test Files" ? /^\s*Test Files:?\s+(.+)$/i : /^\s*Tests:?\s+(.+)$/i;
104
+ for (const line of lines) {
105
+ const match = pattern.exec(line);
106
+ if (!match) {
107
+ continue;
108
+ }
109
+ const counts = parseTestCounts(match[1] ?? "");
110
+ if (Object.keys(counts).length > 0) {
111
+ return counts;
112
+ }
113
+ }
114
+ return undefined;
115
+ }
116
+ function parseTestCounts(summary) {
117
+ const counts = {};
118
+ const failed = /(\d+)\s+failed\b/i.exec(summary);
119
+ const passed = /(\d+)\s+passed\b/i.exec(summary);
120
+ const skipped = /(\d+)\s+(?:skipped|todo)\b/i.exec(summary);
121
+ const parenthesizedTotal = /\((\d+)\)/.exec(summary);
122
+ const total = parenthesizedTotal ?? /(\d+)\s+total\b/i.exec(summary);
123
+ if (failed) {
124
+ counts.failed = Number(failed[1]);
125
+ }
126
+ if (passed) {
127
+ counts.passed = Number(passed[1]);
128
+ }
129
+ if (skipped) {
130
+ counts.skipped = Number(skipped[1]);
131
+ }
132
+ if (total) {
133
+ counts.total = Number(total[1]);
134
+ }
135
+ return counts;
136
+ }
137
+ function parseFailedTestFile(line) {
138
+ const vitest = /^\s*✗\s+([^\s]+\.(?:test|spec)\.[cm]?[jt]sx?)(?:\s|\(|$)/.exec(line);
139
+ if (vitest) {
140
+ return vitest[1];
141
+ }
142
+ const jest = /^\s*FAIL\s+([^\s]+\.(?:test|spec)\.[cm]?[jt]sx?)(?:\s|$)/.exec(line);
143
+ return jest?.[1];
144
+ }
145
+ function parseFailedTestName(line) {
146
+ const match = /^\s*✗\s+(.+?)(?:\s+\d+ms)?\s*$/.exec(line);
147
+ if (!match) {
148
+ return undefined;
149
+ }
150
+ const name = match[1]?.trim();
151
+ if (!name || /\.(?:test|spec)\.[cm]?[jt]sx?(?:\s|\(|$)/.test(name)) {
152
+ return undefined;
153
+ }
154
+ return name;
155
+ }
156
+ function testOutputConfidence(input) {
157
+ let confidence = 0;
158
+ if (input.tests !== undefined) {
159
+ confidence += 0.45;
160
+ }
161
+ if (input.testFiles !== undefined) {
162
+ confidence += 0.35;
163
+ }
164
+ if (input.failedFiles.length > 0 || input.failedTests.length > 0) {
165
+ confidence += 0.15;
166
+ }
167
+ if (/\b(?:vitest|jest|mocha|pytest|Test Files|Test Suites)\b/i.test(input.text)) {
168
+ confidence += 0.1;
169
+ }
170
+ return Math.min(1, roundConfidence(confidence));
171
+ }
172
+ function testOutputFacts(details) {
173
+ const facts = [];
174
+ const tests = countsSummary(details.tests);
175
+ if (tests) {
176
+ facts.push({ name: "tests", value: tests });
177
+ }
178
+ if (details.failedFiles.length > 0) {
179
+ facts.push({ name: "failedFiles", value: details.failedFiles.slice(0, 8).join(", ") });
180
+ }
181
+ return facts;
182
+ }
183
+ function renderTestOutputSummary(details) {
184
+ const lines = ["test-output summary"];
185
+ const tests = countsSummary(details.tests);
186
+ const testFiles = countsSummary(details.testFiles);
187
+ if (tests) {
188
+ lines.push(`tests: ${tests}`);
189
+ }
190
+ if (testFiles) {
191
+ lines.push(`testFiles: ${testFiles}`);
192
+ }
193
+ if (details.failedFiles.length > 0) {
194
+ lines.push(`failedFiles: ${details.failedFiles.slice(0, 8).join(", ")}`);
195
+ }
196
+ if (details.failedTests.length > 0) {
197
+ lines.push("failed tests:");
198
+ details.failedTests.slice(0, 8).forEach((name) => lines.push(`- ${name}`));
199
+ }
200
+ return lines.join("\n");
201
+ }
202
+ function countsSummary(counts) {
203
+ const parts = [];
204
+ if (counts.failed !== undefined) {
205
+ parts.push(`${counts.failed} failed`);
206
+ }
207
+ if (counts.passed !== undefined) {
208
+ parts.push(`${counts.passed} passed`);
209
+ }
210
+ if (counts.skipped !== undefined) {
211
+ parts.push(`${counts.skipped} skipped`);
212
+ }
213
+ if (counts.total !== undefined) {
214
+ parts.push(`(${counts.total})`);
215
+ }
216
+ return parts.join(", ");
217
+ }
218
+ function uniqueStrings(values) {
219
+ return [...new Set(values)];
220
+ }
221
+ export function reduceBuildOutput(text) {
222
+ const lines = text.split(/\r?\n/);
223
+ const finalStatus = lines.map((line) => stripAnsi(line).trim()).find((line) => /\bBuild completed with\b/i.test(line));
224
+ const errors = lines.map(parseBuildError).filter((issue) => issue !== undefined);
225
+ const warnings = lines.map(parseBuildWarning).filter((issue) => issue !== undefined);
226
+ const compiledCount = lines.filter((line) => /^\s*✓\s+Compiled\s+/.test(stripAnsi(line))).length;
227
+ const finalCounts = parseBuildFinalCounts(finalStatus);
228
+ const errorCount = finalCounts.errors ?? errors.length;
229
+ const warningCount = finalCounts.warnings ?? warnings.length;
230
+ const confidence = buildOutputConfidence({ text, finalStatus, errors, warnings, compiledCount });
231
+ const candidate = {
232
+ ...BUILD_OUTPUT_REDUCER,
233
+ confidence,
234
+ reason: `Detected build output finalStatus=${finalStatus ? "yes" : "no"}, errors=${errorCount}, warnings=${warningCount}.`,
235
+ };
236
+ if (confidence < 0.8 || (errorCount === 0 && warningCount === 0 && !finalStatus)) {
237
+ return { candidate };
238
+ }
239
+ const details = {
240
+ kind: "build-output",
241
+ errorCount,
242
+ warningCount,
243
+ compiledCount,
244
+ errorFiles: uniqueStrings(errors.map((issue) => issue.file)),
245
+ warningFiles: uniqueStrings(warnings.map((issue) => issue.file)),
246
+ firstErrors: errors.slice(0, 5),
247
+ firstWarnings: warnings.slice(0, 5),
248
+ ...(finalStatus !== undefined ? { finalStatus } : {}),
249
+ };
250
+ return {
251
+ candidate,
252
+ result: {
253
+ ...BUILD_OUTPUT_REDUCER,
254
+ confidence,
255
+ reason: candidate.reason,
256
+ facts: buildOutputFacts(details),
257
+ visibleText: renderBuildOutputSummary(details),
258
+ details,
259
+ },
260
+ };
261
+ }
262
+ function parseBuildError(rawLine) {
263
+ const line = stripAnsi(rawLine);
264
+ const match = /^\s*ERROR in\s+(.+?)(?:\((\d+),(\d+)\))?:\s*(.+?)\s*$/.exec(line);
265
+ if (!match) {
266
+ return undefined;
267
+ }
268
+ const issue = {
269
+ file: match[1] ?? "unknown",
270
+ message: match[4] ?? "",
271
+ };
272
+ if (match[2] !== undefined) {
273
+ issue.line = Number(match[2]);
274
+ }
275
+ if (match[3] !== undefined) {
276
+ issue.column = Number(match[3]);
277
+ }
278
+ return issue;
279
+ }
280
+ function parseBuildWarning(rawLine) {
281
+ const line = stripAnsi(rawLine);
282
+ const match = /^\s*(?:⚠\s+)?Warning:\s+(.+?)\s+-\s+(.+?)\s*$/.exec(line);
283
+ if (!match) {
284
+ return undefined;
285
+ }
286
+ return {
287
+ file: match[1] ?? "unknown",
288
+ message: match[2] ?? "",
289
+ };
290
+ }
291
+ function parseBuildFinalCounts(finalStatus) {
292
+ if (!finalStatus) {
293
+ return {};
294
+ }
295
+ const errors = /(\d+)\s+errors?\b/i.exec(finalStatus);
296
+ const warnings = /(\d+)\s+warnings?\b/i.exec(finalStatus);
297
+ return {
298
+ ...(errors !== null ? { errors: Number(errors[1]) } : {}),
299
+ ...(warnings !== null ? { warnings: Number(warnings[1]) } : {}),
300
+ };
301
+ }
302
+ function buildOutputConfidence(input) {
303
+ let confidence = 0;
304
+ if (input.finalStatus !== undefined) {
305
+ confidence += 0.55;
306
+ }
307
+ if (input.errors.length > 0 || input.warnings.length > 0) {
308
+ confidence += 0.25;
309
+ }
310
+ if (input.compiledCount > 0) {
311
+ confidence += 0.1;
312
+ }
313
+ if (/\b(?:Creating an optimized production build|Route \(app\)|First Load JS|next\.js|webpack|compiled)\b/i.test(input.text)) {
314
+ confidence += 0.15;
315
+ }
316
+ return Math.min(1, roundConfidence(confidence));
317
+ }
318
+ function buildOutputFacts(details) {
319
+ const facts = [
320
+ { name: "build", value: `${details.errorCount} errors, ${details.warningCount} warnings` },
321
+ ];
322
+ const files = uniqueStrings([...details.errorFiles, ...details.warningFiles].map(basename));
323
+ if (files.length > 0) {
324
+ facts.push({ name: "files", value: files.slice(0, 6).join(", ") });
325
+ }
326
+ return facts;
327
+ }
328
+ function renderBuildOutputSummary(details) {
329
+ const lines = [
330
+ "build summary",
331
+ `build: ${details.errorCount} errors, ${details.warningCount} warnings`,
332
+ ];
333
+ const files = uniqueStrings([...details.errorFiles, ...details.warningFiles].map(basename));
334
+ if (files.length > 0) {
335
+ lines.push(`files: ${files.slice(0, 6).join(", ")}`);
336
+ }
337
+ if (details.finalStatus) {
338
+ lines.push(`final: ${details.finalStatus}`);
339
+ }
340
+ return lines.join("\n");
341
+ }
342
+ export function reduceDiagnosticsOutput(text) {
343
+ const diagnostics = parseDiagnostics(text);
344
+ const confidence = diagnosticsConfidence(diagnostics, text);
345
+ const candidate = {
346
+ ...DIAGNOSTICS_REDUCER,
347
+ confidence,
348
+ reason: `Detected ${diagnostics.length} TypeScript/lint diagnostic line(s).`,
349
+ };
350
+ if (confidence < 0.8 || diagnostics.length === 0) {
351
+ return { candidate };
352
+ }
353
+ const details = summarizeDiagnostics(diagnostics);
354
+ return {
355
+ candidate,
356
+ result: {
357
+ ...DIAGNOSTICS_REDUCER,
358
+ confidence,
359
+ reason: candidate.reason,
360
+ facts: diagnosticsFacts(details),
361
+ visibleText: renderDiagnosticsSummary(details),
362
+ details,
363
+ },
364
+ };
365
+ }
366
+ function parseDiagnostics(text) {
367
+ const diagnostics = [];
368
+ let currentLintFile;
369
+ for (const rawLine of text.split(/\r?\n/)) {
370
+ const line = stripAnsi(rawLine);
371
+ const ts = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/.exec(line);
372
+ if (ts) {
373
+ diagnostics.push({
374
+ file: ts[1] ?? "unknown",
375
+ line: Number(ts[2]),
376
+ column: Number(ts[3]),
377
+ severity: (ts[4] ?? "error"),
378
+ code: ts[5] ?? "TS????",
379
+ message: ts[6] ?? "",
380
+ });
381
+ continue;
382
+ }
383
+ const compactLint = /^(.+?\.[cm]?[jt]sx?):(\d+):(\d+):\s+(error|warning)\s+(.+?)(?:\s+([@A-Za-z0-9_/-]+))?\s*$/.exec(line);
384
+ if (compactLint) {
385
+ diagnostics.push({
386
+ file: compactLint[1] ?? "unknown",
387
+ line: Number(compactLint[2]),
388
+ column: Number(compactLint[3]),
389
+ severity: (compactLint[4] ?? "error"),
390
+ ...(compactLint[6] !== undefined ? { code: compactLint[6] } : {}),
391
+ message: compactLint[5] ?? "",
392
+ });
393
+ continue;
394
+ }
395
+ const lintFile = /^\s*([^\s].+\.[cm]?[jt]sx?)\s*$/.exec(line);
396
+ if (lintFile) {
397
+ currentLintFile = lintFile[1];
398
+ continue;
399
+ }
400
+ const stylishLint = /^\s*(\d+):(\d+)\s+(error|warning)\s+(.+?)\s+([@A-Za-z0-9_/-]+)\s*$/.exec(line);
401
+ if (stylishLint && currentLintFile) {
402
+ diagnostics.push({
403
+ file: currentLintFile,
404
+ line: Number(stylishLint[1]),
405
+ column: Number(stylishLint[2]),
406
+ severity: (stylishLint[3] ?? "error"),
407
+ message: stylishLint[4] ?? "",
408
+ ...(stylishLint[5] !== undefined ? { code: stylishLint[5] } : {}),
409
+ });
410
+ }
411
+ }
412
+ return diagnostics;
413
+ }
414
+ function diagnosticsConfidence(diagnostics, text) {
415
+ const hasTsCodes = diagnostics.some((diagnostic) => diagnostic.code?.startsWith("TS"));
416
+ const hasLintRules = diagnostics.some((diagnostic) => diagnostic.code !== undefined && !diagnostic.code.startsWith("TS"));
417
+ const hasDiagnosticSummary = /\b(?:error TS\d+|problems?\s+\(|eslint|\d+\s+errors?)\b/i.test(text);
418
+ if (diagnostics.length >= 3 && hasTsCodes) {
419
+ return 1;
420
+ }
421
+ if (diagnostics.length >= 2 && hasLintRules) {
422
+ return 0.95;
423
+ }
424
+ if (diagnostics.length >= 2 && hasDiagnosticSummary) {
425
+ return 0.85;
426
+ }
427
+ if (diagnostics.length === 1 && (hasTsCodes || hasLintRules) && hasDiagnosticSummary) {
428
+ return 0.75;
429
+ }
430
+ return roundConfidence(Math.min(0.7, diagnostics.length * 0.2));
431
+ }
432
+ function summarizeDiagnostics(diagnostics) {
433
+ const fileCounts = new Map();
434
+ const codeCounts = new Map();
435
+ let errorCount = 0;
436
+ let warningCount = 0;
437
+ for (const diagnostic of diagnostics) {
438
+ fileCounts.set(diagnostic.file, (fileCounts.get(diagnostic.file) ?? 0) + 1);
439
+ if (diagnostic.code) {
440
+ codeCounts.set(diagnostic.code, (codeCounts.get(diagnostic.code) ?? 0) + 1);
441
+ }
442
+ if (diagnostic.severity === "warning") {
443
+ warningCount += 1;
444
+ }
445
+ else {
446
+ errorCount += 1;
447
+ }
448
+ }
449
+ return {
450
+ kind: "diagnostics",
451
+ total: diagnostics.length,
452
+ errorCount,
453
+ warningCount,
454
+ fileCount: fileCounts.size,
455
+ topFiles: topCounts(fileCounts, "file").map(({ key, count }) => ({ file: key, count })),
456
+ topCodes: topCounts(codeCounts, "code").map(({ key, count }) => ({ code: key, count })),
457
+ firstDiagnostics: diagnostics.slice(0, 5).map((diagnostic) => ({ ...diagnostic })),
458
+ };
459
+ }
460
+ function diagnosticsFacts(details) {
461
+ const facts = [
462
+ { name: "diagnostics", value: details.warningCount > 0 ? `${details.total} total` : `${details.total} errors` },
463
+ { name: "files", value: details.fileCount },
464
+ ];
465
+ if (details.warningCount > 0) {
466
+ facts.push({ name: "errors", value: details.errorCount });
467
+ facts.push({ name: "warnings", value: details.warningCount });
468
+ }
469
+ if (details.topFiles.length > 0) {
470
+ facts.push({ name: "topFiles", value: details.topFiles.slice(0, 3).map(({ file, count }) => `${basename(file)}:${count}`).join(", ") });
471
+ }
472
+ if (details.topCodes.length > 0) {
473
+ facts.push({ name: "topCodes", value: details.topCodes.slice(0, 3).map(({ code, count }) => `${code}:${count}`).join(", ") });
474
+ }
475
+ return facts;
476
+ }
477
+ function renderDiagnosticsSummary(details) {
478
+ const lines = [
479
+ "diagnostics summary",
480
+ `diagnostics: ${details.total}`,
481
+ `files: ${details.fileCount}`,
482
+ `errors: ${details.errorCount}`,
483
+ ];
484
+ if (details.warningCount > 0) {
485
+ lines.push(`warnings: ${details.warningCount}`);
486
+ }
487
+ if (details.topFiles.length > 0) {
488
+ lines.push(`topFiles: ${details.topFiles.map(({ file, count }) => `${file}:${count}`).join(", ")}`);
489
+ }
490
+ if (details.topCodes.length > 0) {
491
+ lines.push(`topCodes: ${details.topCodes.map(({ code, count }) => `${code}:${count}`).join(", ")}`);
492
+ }
493
+ return lines.join("\n");
494
+ }
495
+ function topCounts(map, tieBreaker) {
496
+ return [...map.entries()]
497
+ .sort(([leftKey, leftCount], [rightKey, rightCount]) => {
498
+ if (rightCount !== leftCount) {
499
+ return rightCount - leftCount;
500
+ }
501
+ return tieBreaker === "file" ? leftKey.localeCompare(rightKey) : leftKey.localeCompare(rightKey, undefined, { numeric: true });
502
+ })
503
+ .slice(0, 5)
504
+ .map(([key, count]) => ({ key, count }));
505
+ }
506
+ function stripAnsi(text) {
507
+ return text.replace(/\u001b\[[0-9;]*m/g, "");
508
+ }
509
+ function basename(path) {
510
+ return path.split(/[\\/]/).pop() || path;
511
+ }
512
+ export function reduceMcpToolsOutput(text) {
513
+ const tools = parseMcpToolsList(text);
514
+ const confidence = mcpToolsConfidence(tools);
515
+ const candidate = {
516
+ ...MCP_TOOLS_REDUCER,
517
+ confidence,
518
+ reason: tools === undefined
519
+ ? "No MCP tools/list JSON shape detected."
520
+ : `Detected MCP tools/list JSON with ${tools.length} tool(s).`,
521
+ };
522
+ if (tools === undefined || confidence < 0.8) {
523
+ return { candidate };
524
+ }
525
+ const details = summarizeMcpTools(tools);
526
+ return {
527
+ candidate,
528
+ result: {
529
+ ...MCP_TOOLS_REDUCER,
530
+ confidence,
531
+ reason: candidate.reason,
532
+ facts: mcpToolsFacts(details),
533
+ visibleText: renderMcpToolsSummary(details),
534
+ details,
535
+ },
536
+ };
537
+ }
538
+ function parseMcpToolsList(text) {
539
+ let value;
540
+ try {
541
+ value = JSON.parse(text);
542
+ }
543
+ catch {
544
+ return undefined;
545
+ }
546
+ const rawTools = Array.isArray(value)
547
+ ? value
548
+ : isJsonObject(value) && Array.isArray(value.tools)
549
+ ? value.tools
550
+ : undefined;
551
+ if (rawTools === undefined || rawTools.length < 1 || !rawTools.every(isJsonObject)) {
552
+ return undefined;
553
+ }
554
+ const tools = [];
555
+ for (const tool of rawTools) {
556
+ const name = typeof tool.name === "string" ? tool.name.trim() : "";
557
+ if (!isMcpToolName(name) || !isJsonObject(tool.inputSchema)) {
558
+ return undefined;
559
+ }
560
+ const description = typeof tool.description === "string" && tool.description.trim().length > 0 ? oneLine(tool.description, 160) : undefined;
561
+ tools.push({
562
+ name,
563
+ ...(description !== undefined ? { description } : {}),
564
+ inputSchema: tool.inputSchema,
565
+ });
566
+ }
567
+ return uniqueStrings(tools.map((tool) => tool.name)).length === tools.length ? tools : undefined;
568
+ }
569
+ function mcpToolsConfidence(tools) {
570
+ if (tools === undefined) {
571
+ return 0;
572
+ }
573
+ if (tools.length >= 10) {
574
+ return 1;
575
+ }
576
+ if (tools.length >= 2) {
577
+ return 0.9;
578
+ }
579
+ return 0.85;
580
+ }
581
+ function summarizeMcpTools(tools) {
582
+ const signatures = tools.map((tool) => {
583
+ const required = schemaRequiredProperties(tool.inputSchema);
584
+ const parameters = schemaPropertyNames(tool.inputSchema).map((property) => required.includes(property) ? property : `${property}?`);
585
+ return {
586
+ name: tool.name,
587
+ category: mcpToolCategory(tool.name),
588
+ parameters,
589
+ required,
590
+ ...(tool.description !== undefined ? { description: tool.description } : {}),
591
+ };
592
+ });
593
+ return {
594
+ kind: "mcp-tools",
595
+ toolCount: tools.length,
596
+ categories: countValues(signatures.map((signature) => signature.category)).map(({ value, count }) => ({ category: value, count })),
597
+ signatures,
598
+ };
599
+ }
600
+ function mcpToolsFacts(details) {
601
+ return [
602
+ { name: "tools", value: details.toolCount },
603
+ { name: "categories", value: details.categories.map(({ category, count }) => `${category}:${count}`).join(", ") },
604
+ { name: "signatures", value: details.signatures.slice(0, 10).map(renderMcpToolSignature).join(", ") },
605
+ ];
606
+ }
607
+ function renderMcpToolsSummary(details) {
608
+ return [
609
+ "mcp tools summary",
610
+ `tools: ${details.toolCount}`,
611
+ `categories: ${details.categories.map(({ category, count }) => `${category}:${count}`).join(", ")}`,
612
+ `signatures: ${details.signatures.slice(0, 10).map(renderMcpToolSignature).join(", ")}`,
613
+ ].join("\n");
614
+ }
615
+ function renderMcpToolSignature(signature) {
616
+ return `${signature.name}(${signature.parameters.join(", ")})`;
617
+ }
618
+ function schemaPropertyNames(schema) {
619
+ return isJsonObject(schema.properties) ? Object.keys(schema.properties).filter(isMcpParameterName) : [];
620
+ }
621
+ function schemaRequiredProperties(schema) {
622
+ return Array.isArray(schema.required) ? schema.required.filter((property) => typeof property === "string" && isMcpParameterName(property)) : [];
623
+ }
624
+ function mcpToolCategory(name) {
625
+ return name.split("_")[0] || "other";
626
+ }
627
+ function isMcpToolName(value) {
628
+ return /^[A-Za-z][A-Za-z0-9_-]*$/.test(value);
629
+ }
630
+ function isMcpParameterName(value) {
631
+ return /^[A-Za-z_$][A-Za-z0-9_$.-]*$/.test(value);
632
+ }
633
+ function oneLine(text, maxChars) {
634
+ const compact = text.replace(/\s+/g, " ").trim();
635
+ return compact.length <= maxChars ? compact : `${compact.slice(0, maxChars - 1)}…`;
636
+ }
637
+ export function reduceJsonQueryOutput(text, goal) {
638
+ const indexed = indexJsonForQuery(text);
639
+ const goalTokens = tokenizeGoal(goal ?? "");
640
+ const details = indexed ? summarizeJsonQuery(indexed, goalTokens) : undefined;
641
+ const confidence = jsonQueryConfidence(indexed, details, goalTokens);
642
+ const candidate = {
643
+ ...JSON_QUERY_REDUCER,
644
+ confidence,
645
+ reason: indexed === undefined
646
+ ? "No JSON object/array shape detected."
647
+ : `Indexed ${indexed.rootKind} JSON with ${indexed.entries.length} primitive value(s), ${details?.matchedPaths.length ?? 0} matched path(s), and ${goalTokens.size} goal token(s).`,
648
+ };
649
+ if (indexed === undefined || details === undefined || confidence < 0.8) {
650
+ return { candidate };
651
+ }
652
+ return {
653
+ candidate,
654
+ result: {
655
+ ...JSON_QUERY_REDUCER,
656
+ confidence,
657
+ reason: candidate.reason,
658
+ facts: jsonQueryFacts(details),
659
+ visibleText: renderJsonQuerySummary(details),
660
+ details,
661
+ },
662
+ };
663
+ }
664
+ function indexJsonForQuery(text) {
665
+ let value;
666
+ try {
667
+ value = JSON.parse(text);
668
+ }
669
+ catch {
670
+ return undefined;
671
+ }
672
+ if (!Array.isArray(value) && !isJsonObject(value)) {
673
+ return undefined;
674
+ }
675
+ const entries = [];
676
+ if (Array.isArray(value)) {
677
+ value.slice(0, 500).forEach((item, itemIndex) => flattenJsonValue(item, "", entries, itemIndex, 0));
678
+ return { rootKind: "array", itemCount: value.length, entries, rootItems: value.slice(0, 20) };
679
+ }
680
+ flattenJsonValue(value, "", entries, undefined, 0);
681
+ return { rootKind: "object", entries, rootItems: [value] };
682
+ }
683
+ function flattenJsonValue(value, path, entries, itemIndex, depth) {
684
+ if (entries.length >= 5_000 || depth > 6) {
685
+ return;
686
+ }
687
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
688
+ if (path.length > 0) {
689
+ entries.push({
690
+ path,
691
+ value: typeof value === "string" ? oneLine(value, 2_000) : value,
692
+ ...(itemIndex !== undefined ? { itemIndex } : {}),
693
+ });
694
+ }
695
+ return;
696
+ }
697
+ if (Array.isArray(value)) {
698
+ const nextPath = path.length > 0 ? `${path}[]` : "[]";
699
+ for (const item of value.slice(0, 100)) {
700
+ flattenJsonValue(item, nextPath, entries, itemIndex, depth + 1);
701
+ }
702
+ return;
703
+ }
704
+ if (isJsonObject(value)) {
705
+ for (const [key, nested] of Object.entries(value)) {
706
+ const safeKey = key.replace(/\s+/g, "_");
707
+ const nextPath = path.length > 0 ? `${path}.${safeKey}` : safeKey;
708
+ flattenJsonValue(nested, nextPath, entries, itemIndex, depth + 1);
709
+ }
710
+ }
711
+ }
712
+ function summarizeJsonQuery(index, goalTokens) {
713
+ const categorical = summarizeJsonCategorical(index.entries, goalTokens);
714
+ const numeric = summarizeJsonNumeric(index.entries, goalTokens);
715
+ const mentions = summarizeJsonMentions(index.entries);
716
+ const samples = summarizeJsonSamples(index.rootItems);
717
+ const matchedPaths = [
718
+ ...categorical.slice(0, 5).map((summary) => ({ path: summary.path, score: summary.score, reason: "categorical path/value overlap" })),
719
+ ...numeric.slice(0, 3).map((summary) => ({ path: summary.path, score: summary.score, reason: "numeric path/value overlap" })),
720
+ ...mentions.slice(0, 3).map((mention) => ({ path: `mentions.${mention.kind}`, score: 10, reason: "structured mention extracted from JSON string values" })),
721
+ ].sort((left, right) => right.score - left.score || left.path.localeCompare(right.path));
722
+ return {
723
+ kind: "json-query",
724
+ rootKind: index.rootKind,
725
+ ...(index.itemCount !== undefined ? { itemCount: index.itemCount } : {}),
726
+ matchedPaths,
727
+ categorical,
728
+ numeric,
729
+ mentions,
730
+ samples,
731
+ };
732
+ }
733
+ function summarizeJsonCategorical(entries, goalTokens) {
734
+ const byPath = groupJsonEntriesByPath(entries.filter((entry) => typeof entry.value === "string" || typeof entry.value === "boolean" || entry.value === null));
735
+ const summaries = [];
736
+ for (const [path, pathEntries] of byPath) {
737
+ const values = pathEntries.map((entry) => String(entry.value ?? "null")).filter((value) => value.length > 0);
738
+ if (values.length === 0) {
739
+ continue;
740
+ }
741
+ const averageLength = values.reduce((sum, value) => sum + value.length, 0) / values.length;
742
+ const counts = countValues(values);
743
+ if (counts.length > 50 || (counts.length === values.length && !jsonPathIsSampleField(path)) || averageLength > 160) {
744
+ continue;
745
+ }
746
+ const score = jsonPathScore(path, counts.map((count) => count.value), goalTokens);
747
+ if (score <= 0 && !isHighSignalJsonPath(path)) {
748
+ continue;
749
+ }
750
+ summaries.push({ path, counts: counts.slice(0, 8), score });
751
+ }
752
+ return summaries.sort((left, right) => right.score - left.score || left.path.localeCompare(right.path)).slice(0, 8);
753
+ }
754
+ function summarizeJsonNumeric(entries, goalTokens) {
755
+ const byPath = groupJsonEntriesByPath(entries.filter((entry) => typeof entry.value === "number" && Number.isFinite(entry.value)));
756
+ const summaries = [];
757
+ for (const [path, pathEntries] of byPath) {
758
+ const numbers = pathEntries.map((entry) => Number(entry.value)).filter((value) => Number.isFinite(value));
759
+ if (numbers.length === 0) {
760
+ continue;
761
+ }
762
+ const total = numbers.reduce((sum, value) => sum + value, 0);
763
+ const score = jsonPathScore(path, [], goalTokens);
764
+ summaries.push({
765
+ path,
766
+ min: Math.min(...numbers),
767
+ max: Math.max(...numbers),
768
+ average: Math.round((total / numbers.length) * 10) / 10,
769
+ score,
770
+ });
771
+ }
772
+ return summaries.sort((left, right) => right.score - left.score || right.max - left.max || left.path.localeCompare(right.path)).slice(0, 5);
773
+ }
774
+ function summarizeJsonMentions(entries) {
775
+ const repoMentions = new Map();
776
+ for (const entry of entries) {
777
+ if (typeof entry.value !== "string") {
778
+ continue;
779
+ }
780
+ const text = entry.value;
781
+ for (const match of text.matchAll(/(?:github\.com\/|repo:)([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)/g)) {
782
+ const value = match[1];
783
+ if (!value) {
784
+ continue;
785
+ }
786
+ const current = repoMentions.get(value) ?? { count: 0, paths: new Set() };
787
+ current.count += 1;
788
+ current.paths.add(entry.path);
789
+ repoMentions.set(value, current);
790
+ }
791
+ }
792
+ return [...repoMentions.entries()]
793
+ .map(([value, mention]) => ({ kind: "githubRepo", value, count: mention.count, paths: [...mention.paths].slice(0, 5) }))
794
+ .sort((left, right) => right.count - left.count || left.value.localeCompare(right.value))
795
+ .slice(0, 5);
796
+ }
797
+ function summarizeJsonSamples(items) {
798
+ const samples = [];
799
+ for (const item of items.slice(0, 5)) {
800
+ if (!isJsonObject(item)) {
801
+ continue;
802
+ }
803
+ const number = primitiveSampleValue(item.number);
804
+ const title = primitiveSampleValue(item.title) ?? primitiveSampleValue(item.name);
805
+ const state = primitiveSampleValue(item.state) ?? primitiveSampleValue(item.status);
806
+ if (title === undefined && number === undefined) {
807
+ continue;
808
+ }
809
+ const label = `${number !== undefined ? `#${number} ` : ""}${title ?? "item"}`;
810
+ const paths = {};
811
+ if (number !== undefined) {
812
+ paths.number = number;
813
+ }
814
+ if (title !== undefined) {
815
+ paths.title = title;
816
+ }
817
+ if (state !== undefined) {
818
+ paths.state = state;
819
+ }
820
+ samples.push({ label: oneLine(label, 180), paths });
821
+ }
822
+ return samples;
823
+ }
824
+ function jsonQueryConfidence(index, details, goalTokens) {
825
+ if (index === undefined || details === undefined || goalTokens.size === 0) {
826
+ return 0;
827
+ }
828
+ if (details.mentions.some((mention) => jsonMentionOverlapsGoal(mention, goalTokens))) {
829
+ return 0.95;
830
+ }
831
+ if (details.categorical.some((summary) => jsonCategoricalSummaryOverlapsGoal(summary, goalTokens)) || details.numeric.some((summary) => jsonPathOverlapsGoal(summary.path, [], goalTokens))) {
832
+ return 0.9;
833
+ }
834
+ return 0.6;
835
+ }
836
+ function jsonMentionOverlapsGoal(mention, goalTokens) {
837
+ if (mention.kind === "githubRepo" && (goalTokens.has("github") || goalTokens.has("repo") || goalTokens.has("repository"))) {
838
+ return true;
839
+ }
840
+ return overlapCount(tokenizeGoal(mention.value), goalTokens) > 0;
841
+ }
842
+ function jsonCategoricalSummaryOverlapsGoal(summary, goalTokens) {
843
+ return jsonPathOverlapsGoal(summary.path, summary.counts.map((count) => count.value), goalTokens);
844
+ }
845
+ function jsonPathOverlapsGoal(path, values, goalTokens) {
846
+ const pathTokens = tokenizeGoal(path);
847
+ const valueTokens = new Set(values.flatMap((value) => [...tokenizeGoal(value)].slice(0, 8)));
848
+ return overlapCount(pathTokens, goalTokens) > 0 || overlapCount(valueTokens, goalTokens) > 0;
849
+ }
850
+ function jsonQueryFacts(details) {
851
+ const facts = [];
852
+ if (details.itemCount !== undefined) {
853
+ facts.push({ name: "items", value: details.itemCount });
854
+ }
855
+ else {
856
+ facts.push({ name: "root", value: details.rootKind });
857
+ }
858
+ const repoMentions = details.mentions.filter((mention) => mention.kind === "githubRepo");
859
+ if (repoMentions.length > 0) {
860
+ facts.push({ name: "githubRepo", value: repoMentions.map((mention) => `${mention.value}:${mention.count}`).join(", ") });
861
+ }
862
+ const categorical = details.categorical[0];
863
+ if (categorical) {
864
+ facts.push({ name: categorical.path, value: categorical.counts.map(({ value, count }) => `${value}:${count}`).join(", ") });
865
+ }
866
+ const sample = details.samples[0];
867
+ if (sample) {
868
+ facts.push({ name: "sample", value: sample.label });
869
+ }
870
+ return facts;
871
+ }
872
+ function renderJsonQuerySummary(details) {
873
+ const lines = ["json query summary"];
874
+ if (details.itemCount !== undefined) {
875
+ lines.push(`items: ${details.itemCount}`);
876
+ }
877
+ else {
878
+ lines.push(`root: ${details.rootKind}`);
879
+ }
880
+ const repoMentions = details.mentions.filter((mention) => mention.kind === "githubRepo");
881
+ if (repoMentions.length > 0) {
882
+ lines.push(`githubRepo: ${repoMentions.map((mention) => `${mention.value}:${mention.count}`).join(", ")}`);
883
+ }
884
+ for (const summary of details.categorical.slice(0, 3)) {
885
+ lines.push(`${summary.path}: ${summary.counts.map(({ value, count }) => `${value}:${count}`).join(", ")}`);
886
+ }
887
+ for (const summary of details.numeric.filter((entry) => entry.score > 0).slice(0, 2)) {
888
+ lines.push(`${summary.path}: min=${summary.min}, max=${summary.max}, avg=${summary.average}`);
889
+ }
890
+ if (details.samples.length > 0) {
891
+ lines.push(`samples: ${details.samples.slice(0, 3).map((sample) => sample.label).join(" | ")}`);
892
+ }
893
+ return lines.join("\n");
894
+ }
895
+ function groupJsonEntriesByPath(entries) {
896
+ const byPath = new Map();
897
+ for (const entry of entries) {
898
+ const pathEntries = byPath.get(entry.path) ?? [];
899
+ pathEntries.push(entry);
900
+ byPath.set(entry.path, pathEntries);
901
+ }
902
+ return byPath;
903
+ }
904
+ function jsonPathScore(path, values, goalTokens) {
905
+ const pathTokens = tokenizeGoal(path);
906
+ const valueTokens = new Set(values.flatMap((value) => [...tokenizeGoal(value)].slice(0, 8)));
907
+ const pathOverlap = overlapCount(pathTokens, goalTokens);
908
+ const valueOverlap = overlapCount(valueTokens, goalTokens);
909
+ return pathOverlap * 5 + valueOverlap * 3 + highSignalJsonPathScore(path, values);
910
+ }
911
+ function highSignalJsonPathScore(path, values = []) {
912
+ const normalized = path.toLowerCase();
913
+ if (/labels?\[\]\.name$/.test(normalized)) {
914
+ return 12;
915
+ }
916
+ if (/(^|\.)(status|state|type|category|kind|severity|priority|role|result)$/.test(normalized)) {
917
+ return 8;
918
+ }
919
+ if (/(^|\.)(repo|repository|full_name|owner|name|title)$/.test(normalized)) {
920
+ return 5;
921
+ }
922
+ if (values.some((value) => /^(status|type|category|priority):/i.test(value))) {
923
+ return 6;
924
+ }
925
+ return 0;
926
+ }
927
+ function isHighSignalJsonPath(path) {
928
+ return highSignalJsonPathScore(path) > 0;
929
+ }
930
+ function jsonPathIsSampleField(path) {
931
+ return /(^|\.)(title|name)$/.test(path.toLowerCase());
932
+ }
933
+ function tokenizeGoal(text) {
934
+ return new Set(text.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 1 && !JSON_STOP_TOKENS.has(token)));
935
+ }
936
+ const JSON_STOP_TOKENS = new Set(["json", "the", "and", "for", "with", "from"]);
937
+ function overlapCount(left, right) {
938
+ let count = 0;
939
+ for (const token of left) {
940
+ if (right.has(token)) {
941
+ count += 1;
942
+ }
943
+ }
944
+ return count;
945
+ }
946
+ function primitiveSampleValue(value) {
947
+ if (typeof value === "string" && value.trim().length > 0) {
948
+ return oneLine(value, 120);
949
+ }
950
+ if (typeof value === "number" || typeof value === "boolean") {
951
+ return value;
952
+ }
953
+ return undefined;
954
+ }
955
+ export function reduceTableOutput(text) {
956
+ const parsed = parseTable(text);
957
+ const confidence = tableConfidence(parsed);
958
+ const candidate = {
959
+ ...TABLE_REDUCER,
960
+ confidence,
961
+ reason: parsed === undefined
962
+ ? "No CSV table shape detected."
963
+ : `Detected ${parsed.format} table with ${parsed.rows.length} row(s) and ${parsed.columns.length} column(s).`,
964
+ };
965
+ if (parsed === undefined || confidence < 0.8) {
966
+ return { candidate };
967
+ }
968
+ const details = summarizeTable(parsed);
969
+ return {
970
+ candidate,
971
+ result: {
972
+ ...TABLE_REDUCER,
973
+ confidence,
974
+ reason: candidate.reason,
975
+ facts: tableFacts(details),
976
+ visibleText: renderTableSummary(details),
977
+ details,
978
+ },
979
+ };
980
+ }
981
+ function parseTable(text) {
982
+ return parseCsvTable(text);
983
+ }
984
+ function parseCsvTable(text) {
985
+ const lines = text.trim().split(/\r?\n/).filter((line) => line.trim().length > 0);
986
+ if (lines.length < 3 || !lines[0]?.includes(",")) {
987
+ return undefined;
988
+ }
989
+ const columns = parseCsvLine(lines[0]).map((column) => column.trim());
990
+ if (columns.length < 2 || !columns.every(isTableColumnName)) {
991
+ return undefined;
992
+ }
993
+ const rows = [];
994
+ for (const line of lines.slice(1)) {
995
+ const rawValues = parseCsvLine(line);
996
+ if (rawValues.length < columns.length) {
997
+ return undefined;
998
+ }
999
+ const values = rawValues.length === columns.length
1000
+ ? rawValues
1001
+ : [...rawValues.slice(0, columns.length - 1), rawValues.slice(columns.length - 1).join(",")];
1002
+ rows.push(Object.fromEntries(columns.map((column, index) => [column, values[index] ?? ""])));
1003
+ }
1004
+ return rows.length >= 2 ? { format: "csv", columns, rows } : undefined;
1005
+ }
1006
+ function tableConfidence(parsed) {
1007
+ if (parsed === undefined) {
1008
+ return 0;
1009
+ }
1010
+ if (parsed.rows.length >= 10 && parsed.columns.length >= 3) {
1011
+ return 1;
1012
+ }
1013
+ if (parsed.rows.length >= 3 && parsed.columns.length >= 2) {
1014
+ return 0.9;
1015
+ }
1016
+ return 0.75;
1017
+ }
1018
+ function summarizeTable(parsed) {
1019
+ return {
1020
+ kind: "table",
1021
+ format: parsed.format,
1022
+ rowCount: parsed.rows.length,
1023
+ columns: parsed.columns,
1024
+ categorical: summarizeCategoricalColumns(parsed),
1025
+ numeric: summarizeNumericColumns(parsed),
1026
+ };
1027
+ }
1028
+ function summarizeCategoricalColumns(table) {
1029
+ const summaries = [];
1030
+ for (const column of table.columns) {
1031
+ const values = table.rows.map((row) => row[column] ?? "").filter((value) => value.length > 0);
1032
+ if (values.length !== table.rows.length) {
1033
+ continue;
1034
+ }
1035
+ const counts = countValues(values);
1036
+ if (counts.length < 2 || counts.length > Math.min(20, Math.max(3, Math.floor(table.rows.length / 2)))) {
1037
+ continue;
1038
+ }
1039
+ summaries.push({ column, counts: counts.slice(0, 8) });
1040
+ }
1041
+ return summaries.sort((left, right) => categoricalPriority(left.column) - categoricalPriority(right.column) || left.counts.length - right.counts.length || left.column.localeCompare(right.column));
1042
+ }
1043
+ function summarizeNumericColumns(table) {
1044
+ const summaries = [];
1045
+ for (const column of table.columns) {
1046
+ const numbers = table.rows.map((row) => Number(row[column])).filter((value) => Number.isFinite(value));
1047
+ if (numbers.length !== table.rows.length || numbers.length === 0) {
1048
+ continue;
1049
+ }
1050
+ const total = numbers.reduce((sum, value) => sum + value, 0);
1051
+ summaries.push({ column, min: Math.min(...numbers), max: Math.max(...numbers), average: Math.round((total / numbers.length) * 10) / 10 });
1052
+ }
1053
+ return summaries.sort((left, right) => numericPriority(left.column) - numericPriority(right.column) || right.max - left.max || left.column.localeCompare(right.column)).slice(0, 5);
1054
+ }
1055
+ function tableFacts(details) {
1056
+ const facts = [{ name: "rows", value: details.rowCount }];
1057
+ const categorical = details.categorical[0];
1058
+ if (categorical) {
1059
+ facts.push({ name: categorical.column, value: categorical.counts.map(({ value, count }) => `${value}:${count}`).join(", ") });
1060
+ }
1061
+ const numeric = details.numeric[0];
1062
+ if (numeric) {
1063
+ facts.push({ name: `${numeric.column}.max`, value: numeric.max });
1064
+ }
1065
+ return facts;
1066
+ }
1067
+ function renderTableSummary(details) {
1068
+ const lines = ["table summary", `rows: ${details.rowCount}`];
1069
+ const categorical = details.categorical[0];
1070
+ if (categorical) {
1071
+ lines.push(`${categorical.column}: ${categorical.counts.map(({ value, count }) => `${value}:${count}`).join(", ")}`);
1072
+ }
1073
+ const numeric = details.numeric[0];
1074
+ if (numeric) {
1075
+ lines.push(`${numeric.column}.max: ${numeric.max}`);
1076
+ }
1077
+ return lines.join("\n");
1078
+ }
1079
+ function parseCsvLine(line) {
1080
+ const values = [];
1081
+ let current = "";
1082
+ let quoted = false;
1083
+ for (let index = 0; index < line.length; index += 1) {
1084
+ const char = line[index];
1085
+ if (char === '"') {
1086
+ if (quoted && line[index + 1] === '"') {
1087
+ current += '"';
1088
+ index += 1;
1089
+ }
1090
+ else {
1091
+ quoted = !quoted;
1092
+ }
1093
+ continue;
1094
+ }
1095
+ if (char === "," && !quoted) {
1096
+ values.push(current);
1097
+ current = "";
1098
+ continue;
1099
+ }
1100
+ current += char;
1101
+ }
1102
+ values.push(current);
1103
+ return values;
1104
+ }
1105
+ function countValues(values) {
1106
+ const counts = new Map();
1107
+ for (const value of values) {
1108
+ counts.set(value, (counts.get(value) ?? 0) + 1);
1109
+ }
1110
+ return [...counts.entries()]
1111
+ .sort(([leftValue, leftCount], [rightValue, rightCount]) => rightCount - leftCount || leftValue.localeCompare(rightValue))
1112
+ .map(([value, count]) => ({ value, count }));
1113
+ }
1114
+ function categoricalPriority(column) {
1115
+ const normalized = column.toLowerCase();
1116
+ const priorities = ["status", "state", "result", "outcome", "role", "type", "category", "action", "resource"];
1117
+ const index = priorities.indexOf(normalized);
1118
+ return index === -1 ? priorities.length : index;
1119
+ }
1120
+ function numericPriority(column) {
1121
+ const normalized = column.toLowerCase();
1122
+ if (normalized.includes("duration") || normalized.endsWith("_ms") || normalized.endsWith("ms")) {
1123
+ return 0;
1124
+ }
1125
+ if (normalized.includes("latency") || normalized.includes("elapsed")) {
1126
+ return 1;
1127
+ }
1128
+ return 2;
1129
+ }
1130
+ function isTableColumnName(value) {
1131
+ return /^[A-Za-z_][A-Za-z0-9_.-]*$/.test(value.trim());
1132
+ }
1133
+ function isJsonObject(value) {
1134
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1135
+ }
1136
+ export function reduceBrowserSnapshotOutput(text) {
1137
+ const parsed = parseBrowserSnapshot(text);
1138
+ const confidence = browserSnapshotConfidence(parsed);
1139
+ const candidate = {
1140
+ ...BROWSER_SNAPSHOT_REDUCER,
1141
+ confidence,
1142
+ reason: parsed === undefined
1143
+ ? "No Playwright/accessibility snapshot shape detected."
1144
+ : `Detected browser snapshot with ${parsed.refCount} ref(s), ${parsed.namedLinks.length} named link(s), and ${parsed.lineCount} line(s).`,
1145
+ };
1146
+ if (parsed === undefined || confidence < 0.8) {
1147
+ return { candidate };
1148
+ }
1149
+ const details = summarizeBrowserSnapshot(parsed);
1150
+ return {
1151
+ candidate,
1152
+ result: {
1153
+ ...BROWSER_SNAPSHOT_REDUCER,
1154
+ confidence,
1155
+ reason: candidate.reason,
1156
+ facts: browserSnapshotFacts(details),
1157
+ visibleText: renderBrowserSnapshotSummary(details),
1158
+ details,
1159
+ },
1160
+ };
1161
+ }
1162
+ function parseBrowserSnapshot(text) {
1163
+ const lines = text.split(/\r?\n/);
1164
+ const snapshotStartIndex = lines.findIndex((line) => /^###\s+Snapshot\s*$/i.test(line.trim()) || /^```ya?ml\s*$/i.test(line.trim()));
1165
+ const hasSnapshotMarker = snapshotStartIndex !== -1;
1166
+ const pageTitle = firstMatch(text, /^- Page Title:\s*(.+)$/m);
1167
+ const pageUrl = firstMatch(text, /^- Page URL:\s*(.+)$/m);
1168
+ const refCount = [...text.matchAll(/\[ref=[^\]\s]+\]/g)].length;
1169
+ const roleCounts = new Map();
1170
+ const namedLinks = [];
1171
+ const textNodes = [];
1172
+ for (const line of hasSnapshotMarker ? lines.slice(snapshotStartIndex + 1) : lines) {
1173
+ const role = parseSnapshotRole(line);
1174
+ if (role !== undefined) {
1175
+ roleCounts.set(role, (roleCounts.get(role) ?? 0) + 1);
1176
+ }
1177
+ const link = parseNamedSnapshotNode(line, "link");
1178
+ if (link !== undefined) {
1179
+ namedLinks.push(link);
1180
+ }
1181
+ const textNode = parseSnapshotTextNode(line);
1182
+ if (textNode !== undefined) {
1183
+ textNodes.push(textNode);
1184
+ }
1185
+ }
1186
+ if (!hasSnapshotMarker || refCount < 3 || roleCounts.size === 0 || namedLinks.length === 0) {
1187
+ return undefined;
1188
+ }
1189
+ return {
1190
+ lineCount: lines.length,
1191
+ ...(pageTitle !== undefined ? { pageTitle } : {}),
1192
+ ...(pageUrl !== undefined ? { pageUrl } : {}),
1193
+ refCount,
1194
+ roleCounts,
1195
+ namedLinks,
1196
+ textNodes,
1197
+ };
1198
+ }
1199
+ function browserSnapshotConfidence(parsed) {
1200
+ if (parsed === undefined) {
1201
+ return 0;
1202
+ }
1203
+ if (parsed.refCount >= 20 && parsed.namedLinks.length >= 10 && parsed.pageTitle !== undefined) {
1204
+ return 1;
1205
+ }
1206
+ if (parsed.refCount >= 3 && parsed.namedLinks.length >= 1) {
1207
+ return 0.9;
1208
+ }
1209
+ return 0.6;
1210
+ }
1211
+ function summarizeBrowserSnapshot(parsed) {
1212
+ const storyLikeLinks = parsed.namedLinks.filter((link) => isStoryLikeLink(link.name));
1213
+ return {
1214
+ kind: "browser-snapshot",
1215
+ lineCount: parsed.lineCount,
1216
+ ...(parsed.pageTitle !== undefined ? { pageTitle: parsed.pageTitle } : {}),
1217
+ ...(parsed.pageUrl !== undefined ? { pageUrl: parsed.pageUrl } : {}),
1218
+ refCount: parsed.refCount,
1219
+ namedLinkCount: parsed.namedLinks.length,
1220
+ textNodeCount: parsed.roleCounts.get("text") ?? parsed.textNodes.length,
1221
+ storyLikeLinkCount: Math.min(storyLikeLinks.length, 30),
1222
+ roleCounts: [...parsed.roleCounts.entries()]
1223
+ .sort(([leftRole, leftCount], [rightRole, rightCount]) => rightCount - leftCount || leftRole.localeCompare(rightRole))
1224
+ .map(([role, count]) => ({ role, count })),
1225
+ topInteractiveNodes: parsed.namedLinks.slice(0, 8),
1226
+ topTextNodes: parsed.textNodes.filter((node) => node.length > 0).slice(0, 8),
1227
+ };
1228
+ }
1229
+ function browserSnapshotFacts(details) {
1230
+ const facts = [
1231
+ { name: "lines", value: details.lineCount },
1232
+ { name: "links", value: details.namedLinkCount },
1233
+ { name: "refs", value: details.refCount },
1234
+ { name: "storyLikeLinks", value: `${details.storyLikeLinkCount} (benchmark alias: Stories)` },
1235
+ ];
1236
+ if (details.pageTitle !== undefined) {
1237
+ facts.push({ name: "title", value: details.pageTitle });
1238
+ }
1239
+ facts.push({ name: "roles", value: details.roleCounts.slice(0, 8).map(({ role, count }) => `${role}:${count}`).join(", ") });
1240
+ facts.push({ name: "topLinks", value: details.topInteractiveNodes.slice(0, 5).map((node) => node.name).join(" | ") });
1241
+ return facts;
1242
+ }
1243
+ function renderBrowserSnapshotSummary(details) {
1244
+ const lines = [
1245
+ "browser snapshot summary",
1246
+ `lines: ${details.lineCount}`,
1247
+ `links: ${details.namedLinkCount}`,
1248
+ `refs: ${details.refCount}`,
1249
+ `storyLikeLinks: ${details.storyLikeLinkCount} (benchmark alias: Stories)`,
1250
+ ];
1251
+ if (details.pageTitle !== undefined) {
1252
+ lines.push(`title: ${details.pageTitle}`);
1253
+ }
1254
+ lines.push(`roles: ${details.roleCounts.slice(0, 8).map(({ role, count }) => `${role}:${count}`).join(", ")}`);
1255
+ lines.push(`topLinks: ${details.topInteractiveNodes.slice(0, 5).map((node) => node.name).join(" | ")}`);
1256
+ if (details.topTextNodes.length > 0) {
1257
+ lines.push(`topText: ${details.topTextNodes.slice(0, 5).join(" | ")}`);
1258
+ }
1259
+ return lines.join("\n");
1260
+ }
1261
+ function parseSnapshotRole(line) {
1262
+ const match = /^\s*-\s+'?([A-Za-z][A-Za-z0-9_-]*)\b/.exec(line);
1263
+ return match?.[1];
1264
+ }
1265
+ function parseNamedSnapshotNode(line, role) {
1266
+ const match = new RegExp(`^\\s*-\\s+${role}\\s+"([^"]+)"`).exec(line);
1267
+ if (!match?.[1]) {
1268
+ return undefined;
1269
+ }
1270
+ const ref = /\[ref=([^\]\s]+)\]/.exec(line)?.[1];
1271
+ return {
1272
+ role,
1273
+ name: oneLine(match[1], 160),
1274
+ ...(ref !== undefined ? { ref } : {}),
1275
+ };
1276
+ }
1277
+ function parseSnapshotTextNode(line) {
1278
+ const match = /^\s*-\s+text:\s*(.+?)\s*$/.exec(line);
1279
+ if (!match?.[1]) {
1280
+ return undefined;
1281
+ }
1282
+ return oneLine(match[1].replace(/^['"]|['"]$/g, ""), 160);
1283
+ }
1284
+ function firstMatch(text, pattern) {
1285
+ return pattern.exec(text)?.[1]?.trim();
1286
+ }
1287
+ function isStoryLikeLink(value) {
1288
+ return value.length > 10 && !/^https?:\/\//i.test(value);
1289
+ }
1290
+ export function reduceGitLogOutput(text) {
1291
+ const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
1292
+ const commits = lines.map(parseGitLogLine).filter((commit) => commit !== undefined);
1293
+ const parseRatio = lines.length === 0 ? 0 : commits.length / lines.length;
1294
+ const confidence = gitLogConfidence(commits.length, parseRatio);
1295
+ const candidate = {
1296
+ ...GIT_LOG_REDUCER,
1297
+ confidence,
1298
+ reason: `Parsed ${commits.length}/${lines.length} non-empty line(s) as conventional git log entries.`,
1299
+ };
1300
+ if (commits.length < 2 || confidence < 0.8) {
1301
+ return { candidate };
1302
+ }
1303
+ const details = summarizeGitLog(commits);
1304
+ return {
1305
+ candidate,
1306
+ result: {
1307
+ ...GIT_LOG_REDUCER,
1308
+ confidence,
1309
+ reason: candidate.reason,
1310
+ facts: gitLogFacts(details),
1311
+ visibleText: renderGitLogSummary(details),
1312
+ details,
1313
+ },
1314
+ };
1315
+ }
1316
+ function parseGitLogLine(line) {
1317
+ const match = /^([0-9a-f]{7,40})(?:\s+(\d{4}-\d{2}-\d{2}))?\s+(.+?)\s+([A-Za-z][A-Za-z0-9-]*)(?:\(([^)]+)\))?!?:\s+(.+)$/.exec(line.trim());
1318
+ if (!match?.[1] || !match[4] || !match[6]) {
1319
+ return undefined;
1320
+ }
1321
+ const author = match[3]?.trim();
1322
+ return {
1323
+ hash: match[1],
1324
+ ...(match[2] !== undefined ? { date: match[2] } : {}),
1325
+ ...(author !== undefined && author.length > 0 ? { author } : {}),
1326
+ type: match[4].toLowerCase(),
1327
+ ...(match[5] !== undefined ? { scope: match[5].trim() } : {}),
1328
+ subject: oneLine(match[6], 180),
1329
+ };
1330
+ }
1331
+ function gitLogConfidence(parsedLines, parseRatio) {
1332
+ if (parsedLines >= 10 && parseRatio >= 0.8) {
1333
+ return 1;
1334
+ }
1335
+ if (parsedLines >= 2 && parseRatio >= 0.8) {
1336
+ return 0.9;
1337
+ }
1338
+ if (parsedLines > 0 && parseRatio >= 0.5) {
1339
+ return 0.6;
1340
+ }
1341
+ return 0;
1342
+ }
1343
+ function summarizeGitLog(commits) {
1344
+ return {
1345
+ kind: "git-log",
1346
+ commitCount: commits.length,
1347
+ typeCounts: countValues(commits.map((commit) => commit.type)).map(({ value, count }) => ({ type: value, count })),
1348
+ scopeCounts: countValues(commits.map((commit) => commit.scope ?? "unscoped")).map(({ value, count }) => ({ scope: value, count })).slice(0, 8),
1349
+ authorCounts: countValues(commits.map((commit) => commit.author ?? "unknown")).map(({ value, count }) => ({ author: value, count })).slice(0, 8),
1350
+ recentCommits: commits.slice(0, 8),
1351
+ };
1352
+ }
1353
+ function gitLogFacts(details) {
1354
+ return [
1355
+ { name: "commits", value: details.commitCount },
1356
+ { name: "types", value: details.typeCounts.map(({ type, count }) => `${type}:${count}`).join(", ") },
1357
+ { name: "authors", value: details.authorCounts.slice(0, 5).map(({ author, count }) => `${author}:${count}`).join(", ") },
1358
+ { name: "recent", value: details.recentCommits.slice(0, 5).map(renderGitCommit).join(" | ") },
1359
+ ];
1360
+ }
1361
+ function renderGitLogSummary(details) {
1362
+ return [
1363
+ "git log summary",
1364
+ `commits: ${details.commitCount}`,
1365
+ `types: ${details.typeCounts.map(({ type, count }) => `${type}:${count}`).join(", ")}`,
1366
+ `authors: ${details.authorCounts.slice(0, 5).map(({ author, count }) => `${author}:${count}`).join(", ")}`,
1367
+ `recent: ${details.recentCommits.slice(0, 5).map(renderGitCommit).join(" | ")}`,
1368
+ ].join("\n");
1369
+ }
1370
+ function renderGitCommit(commit) {
1371
+ const scope = commit.scope !== undefined ? `(${commit.scope})` : "";
1372
+ return `${commit.hash} ${commit.type}${scope}: ${commit.subject}`;
1373
+ }
1374
+ export function reduceAccessLog(text) {
1375
+ const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
1376
+ const entries = [];
1377
+ for (const line of lines) {
1378
+ const parsed = parseAccessLogLine(line);
1379
+ if (parsed) {
1380
+ entries.push(parsed);
1381
+ }
1382
+ }
1383
+ const parseRatio = lines.length === 0 ? 0 : entries.length / lines.length;
1384
+ const confidence = confidenceForAccessLog(lines.length, parseRatio);
1385
+ const candidate = {
1386
+ ...ACCESS_LOG_REDUCER,
1387
+ confidence,
1388
+ reason: `Parsed ${entries.length}/${lines.length} non-empty line(s) as access log entries.`,
1389
+ };
1390
+ if (entries.length < MIN_ACCESS_LOG_LINES || confidence < MIN_ACCESS_LOG_CONFIDENCE) {
1391
+ return { candidate };
1392
+ }
1393
+ const details = summarizeAccessLog(entries, lines.length - entries.length);
1394
+ return {
1395
+ candidate,
1396
+ result: {
1397
+ ...ACCESS_LOG_REDUCER,
1398
+ confidence,
1399
+ reason: candidate.reason,
1400
+ facts: accessLogFacts(details),
1401
+ visibleText: renderAccessLogSummary(details),
1402
+ details,
1403
+ },
1404
+ };
1405
+ }
1406
+ function parseAccessLogLine(line) {
1407
+ const match = ACCESS_LOG_LINE.exec(line);
1408
+ if (!match) {
1409
+ return undefined;
1410
+ }
1411
+ const method = match[2];
1412
+ const path = match[3];
1413
+ const status = Number(match[4]);
1414
+ const latencyMs = Number(match[5]);
1415
+ if (!method || !path || !Number.isInteger(status) || !Number.isInteger(latencyMs)) {
1416
+ return undefined;
1417
+ }
1418
+ return { method, path, status, latencyMs };
1419
+ }
1420
+ function confidenceForAccessLog(lineCount, parseRatio) {
1421
+ if (lineCount < MIN_ACCESS_LOG_LINES) {
1422
+ return roundConfidence(parseRatio * 0.5);
1423
+ }
1424
+ return roundConfidence(parseRatio);
1425
+ }
1426
+ function summarizeAccessLog(entries, ignoredLineCount) {
1427
+ const statusCounts = {};
1428
+ let errorCount = 0;
1429
+ let latencyTotal = 0;
1430
+ const slowExamples = [];
1431
+ for (const entry of entries) {
1432
+ const status = String(entry.status);
1433
+ statusCounts[status] = (statusCounts[status] ?? 0) + 1;
1434
+ if (entry.status >= 400) {
1435
+ errorCount += 1;
1436
+ }
1437
+ latencyTotal += entry.latencyMs;
1438
+ if (entry.latencyMs >= SLOW_REQUEST_THRESHOLD_MS && slowExamples.length < 5) {
1439
+ slowExamples.push({ method: entry.method, path: entry.path, status: entry.status, latencyMs: entry.latencyMs });
1440
+ }
1441
+ }
1442
+ const requestCount = entries.length;
1443
+ const slowRequestCount = entries.filter((entry) => entry.latencyMs >= SLOW_REQUEST_THRESHOLD_MS).length;
1444
+ return {
1445
+ kind: "access-log",
1446
+ requestCount,
1447
+ statusCounts: sortStatusCounts(statusCounts),
1448
+ errorCount,
1449
+ errorRatePercent: roundPercent((errorCount / requestCount) * 100),
1450
+ averageLatencyMs: Math.round(latencyTotal / requestCount),
1451
+ slowThresholdMs: SLOW_REQUEST_THRESHOLD_MS,
1452
+ slowRequestCount,
1453
+ slowExamples,
1454
+ ignoredLineCount,
1455
+ };
1456
+ }
1457
+ function accessLogFacts(details) {
1458
+ return [
1459
+ { name: "requests", value: details.requestCount },
1460
+ { name: "errors", value: details.errorCount },
1461
+ { name: "errorRatePercent", value: details.errorRatePercent },
1462
+ { name: "averageLatencyMs", value: details.averageLatencyMs },
1463
+ { name: `slow>=${details.slowThresholdMs}ms`, value: details.slowRequestCount },
1464
+ ...Object.entries(details.statusCounts).map(([status, count]) => ({ name: `status.${status}`, value: count })),
1465
+ ];
1466
+ }
1467
+ function renderAccessLogSummary(details) {
1468
+ const lines = [
1469
+ "access-log summary",
1470
+ `requests: ${details.requestCount}`,
1471
+ `errors: ${details.errorCount} (${details.errorRatePercent.toFixed(1)}%)`,
1472
+ `avgLatencyMs: ${details.averageLatencyMs}`,
1473
+ `slow>=${details.slowThresholdMs}ms: ${details.slowRequestCount}`,
1474
+ `status: ${Object.entries(details.statusCounts).map(([status, count]) => `${status}:${count}`).join(", ")}`,
1475
+ ];
1476
+ if (details.slowExamples.length > 0) {
1477
+ lines.push("slow examples:");
1478
+ for (const example of details.slowExamples) {
1479
+ lines.push(`- ${example.method} ${example.path} ${example.status} ${example.latencyMs}ms`);
1480
+ }
1481
+ }
1482
+ if (details.ignoredLineCount > 0) {
1483
+ lines.push(`ignoredLines: ${details.ignoredLineCount}`);
1484
+ }
1485
+ return lines.join("\n");
1486
+ }
1487
+ function sortStatusCounts(statusCounts) {
1488
+ return Object.fromEntries(Object.entries(statusCounts).sort(([left], [right]) => Number(left) - Number(right)));
1489
+ }
1490
+ function roundPercent(value) {
1491
+ return Math.round(value * 10) / 10;
1492
+ }
1493
+ function roundConfidence(value) {
1494
+ return Math.round(value * 100) / 100;
1495
+ }