@hassangameryt/freeflow 0.7.3 → 0.9.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 (426) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +2 -2
  4. package/.codex-plugin/plugin.json +3 -3
  5. package/.cursor-plugin/plugin.json +1 -1
  6. package/NOTICE +14 -0
  7. package/README.md +101 -159
  8. package/capabilities/cognitive-routing/SKILL.md +47 -210
  9. package/capabilities/cognitive-routing/references/coordinator.md +163 -0
  10. package/capabilities/cognitive-routing/references/worker.md +38 -0
  11. package/capabilities/compaction/SKILL.md +49 -0
  12. package/capabilities/compaction/references/summary-format.md +250 -0
  13. package/capabilities/messaging/SKILL.md +49 -0
  14. package/capabilities/task-memory/SKILL.md +87 -0
  15. package/command-surface.json +8 -52
  16. package/gemini-extension.json +1 -1
  17. package/hooks/claude/hooks.json +13 -3
  18. package/hooks/codex/hooks.json +2 -1
  19. package/hooks/shared/runtime-context.mjs +73 -83
  20. package/licenses/Apache-2.0.txt +55 -0
  21. package/package.json +42 -12
  22. package/pi-extension/README.md +41 -0
  23. package/pi-extension/dist/ask-user/ask.js +108 -0
  24. package/pi-extension/dist/ask-user/form.js +250 -0
  25. package/pi-extension/dist/ask-user/questions.js +66 -0
  26. package/pi-extension/dist/ask-user/tool.js +124 -0
  27. package/pi-extension/dist/cognitive-routing/assembler.js +417 -0
  28. package/pi-extension/dist/cognitive-routing/bootstrap.js +90 -0
  29. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/config.js +8 -6
  30. package/pi-extension/dist/cognitive-routing/economics.js +45 -0
  31. package/pi-extension/dist/cognitive-routing/event-schema.js +388 -0
  32. package/pi-extension/dist/{session-sources/events.js → cognitive-routing/event-store.js} +107 -41
  33. package/pi-extension/dist/cognitive-routing/gate.js +256 -0
  34. package/pi-extension/dist/cognitive-routing/handlers.js +901 -0
  35. package/pi-extension/dist/cognitive-routing/handoffs.js +350 -0
  36. package/pi-extension/dist/cognitive-routing/model-control.js +476 -0
  37. package/pi-extension/dist/cognitive-routing/projection.js +520 -0
  38. package/pi-extension/dist/cognitive-routing/provenance.js +83 -0
  39. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/render.js +15 -15
  40. package/pi-extension/dist/cognitive-routing/runtime.js +398 -0
  41. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/schemas.js +47 -11
  42. package/pi-extension/dist/cognitive-routing/session.js +223 -0
  43. package/pi-extension/dist/{session-sources → cognitive-routing}/sources.js +126 -87
  44. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/state.js +55 -386
  45. package/pi-extension/dist/cognitive-routing/status.js +81 -0
  46. package/pi-extension/dist/cognitive-routing/tools.js +74 -0
  47. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/types.js +14 -11
  48. package/pi-extension/dist/compaction/carry.js +205 -0
  49. package/pi-extension/dist/compaction/config.js +24 -0
  50. package/pi-extension/dist/compaction/controller.js +494 -0
  51. package/pi-extension/dist/compaction/harness.js +93 -0
  52. package/pi-extension/dist/compaction/results.js +159 -0
  53. package/pi-extension/dist/compaction/thresholds.js +35 -0
  54. package/pi-extension/dist/compaction/tool.js +57 -0
  55. package/pi-extension/dist/host/branch.js +13 -0
  56. package/pi-extension/dist/host/canonical.js +12 -0
  57. package/pi-extension/dist/host/catalog.js +62 -0
  58. package/pi-extension/dist/host/config-validation.js +233 -0
  59. package/pi-extension/dist/host/config.js +361 -0
  60. package/pi-extension/dist/host/inbound.js +142 -0
  61. package/pi-extension/dist/host/projection-tags.js +60 -0
  62. package/pi-extension/dist/host/prompts.js +93 -0
  63. package/pi-extension/dist/{session-sources → host}/read-only-session.js +117 -1
  64. package/pi-extension/dist/{runtime → host}/request-history.js +125 -39
  65. package/pi-extension/dist/host/rows.js +25 -0
  66. package/pi-extension/dist/host/runtime-state.js +204 -0
  67. package/pi-extension/dist/host/section-keeper.js +85 -0
  68. package/pi-extension/dist/host/settings/freeflow-command.js +2323 -0
  69. package/pi-extension/dist/{settings/settings-tui.js → host/settings/settings-view.js} +205 -73
  70. package/pi-extension/dist/host/staging.js +28 -0
  71. package/pi-extension/dist/host/status.js +115 -0
  72. package/pi-extension/dist/index.js +1004 -188
  73. package/pi-extension/dist/messaging/config.js +27 -0
  74. package/pi-extension/dist/messaging/messaging.js +398 -0
  75. package/pi-extension/dist/messaging/registry.js +57 -0
  76. package/pi-extension/dist/messaging/render.js +90 -0
  77. package/pi-extension/dist/messaging/tools.js +109 -0
  78. package/pi-extension/dist/messaging/transport.js +101 -0
  79. package/pi-extension/dist/provider-support/cache/anchor.js +21 -0
  80. package/pi-extension/dist/provider-support/cache/anthropic.js +102 -0
  81. package/pi-extension/dist/provider-support/cache/health.js +73 -0
  82. package/pi-extension/dist/provider-support/cache/index.js +58 -0
  83. package/pi-extension/dist/provider-support/cache/keepalive.js +222 -0
  84. package/pi-extension/dist/provider-support/cache/monitor.js +17 -0
  85. package/pi-extension/dist/provider-support/cache/openai-responses.js +48 -0
  86. package/pi-extension/dist/provider-support/effort.js +13 -0
  87. package/pi-extension/dist/provider-support/index.js +44 -3
  88. package/pi-extension/dist/provider-support/{astra → openai}/adapter.js +46 -29
  89. package/pi-extension/dist/provider-support/{astra → openai}/history.js +10 -8
  90. package/pi-extension/dist/provider-support/{astra → openai}/index.js +8 -4
  91. package/pi-extension/dist/provider-support/{astra → openai}/session-state.js +29 -38
  92. package/pi-extension/dist/provider-support/routes.js +17 -0
  93. package/pi-extension/dist/task-memory/config.js +49 -0
  94. package/pi-extension/dist/task-memory/registry.js +119 -0
  95. package/pi-extension/dist/task-memory/render.js +107 -0
  96. package/pi-extension/dist/task-memory/runtime.js +994 -0
  97. package/pi-extension/dist/task-memory/tool.js +233 -0
  98. package/pi-extension/dist/tool-execution/apply-patch/grammar.js +23 -0
  99. package/pi-extension/dist/tool-execution/apply-patch/match.js +38 -0
  100. package/pi-extension/dist/tool-execution/apply-patch/parser.js +177 -0
  101. package/pi-extension/dist/tool-execution/apply-patch/plan.js +201 -0
  102. package/pi-extension/dist/tool-execution/apply-patch/tool.js +84 -0
  103. package/pi-extension/dist/tool-execution/background.js +430 -0
  104. package/pi-extension/dist/tool-execution/bash-guard.js +23 -0
  105. package/pi-extension/dist/tool-execution/config.js +33 -0
  106. package/pi-extension/dist/tool-execution/edit-messages.js +120 -0
  107. package/pi-extension/dist/tool-execution/file-state.js +138 -0
  108. package/pi-extension/dist/tool-execution/file-tracking.js +163 -0
  109. package/pi-extension/dist/tool-execution/guidance-notices.js +124 -0
  110. package/pi-extension/dist/tool-execution/prompt.js +54 -0
  111. package/pi-extension/dist/tool-execution/skill-reads.js +143 -0
  112. package/pi-extension/dist/tool-execution/tools.js +16 -0
  113. package/pi-extension/freeflow/README.md +9 -0
  114. package/runtime/prompts/cognitive-routing.md +4 -4
  115. package/runtime/prompts/core.md +29 -72
  116. package/runtime/prompts/interaction-contract.md +18 -8
  117. package/runtime/prompts/tool-execution.md +25 -0
  118. package/runtime/prompts/working-method.md +25 -0
  119. package/skills/deliver-work/SKILL.md +76 -0
  120. package/skills/deliver-work/references/branch-closeout.md +134 -0
  121. package/skills/deliver-work/references/commit.md +83 -0
  122. package/skills/deliver-work/references/launch.md +94 -0
  123. package/skills/deliver-work/references/release.md +85 -0
  124. package/skills/deliver-work/scripts/commit-state.mjs +139 -0
  125. package/skills/deliver-work/scripts/delivery-state.mjs +107 -0
  126. package/skills/deliver-work/scripts/lib/git-state.mjs +178 -0
  127. package/skills/deliver-work/scripts/push-route.mjs +122 -0
  128. package/skills/deliver-work/scripts/release-preflight.mjs +177 -0
  129. package/skills/discuss-work/SKILL.md +148 -0
  130. package/skills/{discuss → discuss-work}/references/discussion-continuity.md +13 -50
  131. package/skills/discuss-work/references/learning-action.md +36 -0
  132. package/skills/discuss-work/scripts/choices.mjs +101 -0
  133. package/skills/discuss-work/scripts/lib/choices.mjs +159 -0
  134. package/skills/evaluate-behavior/SKILL.md +107 -0
  135. package/skills/evaluate-behavior/references/authoring.md +381 -0
  136. package/skills/evaluate-behavior/references/coding-tasks.md +145 -0
  137. package/skills/evaluate-behavior/references/conversations-pipelines-judges.md +177 -0
  138. package/skills/evaluate-behavior/references/design-and-measurement.md +273 -0
  139. package/skills/evaluate-behavior/references/running-and-evidence.md +245 -0
  140. package/skills/evaluate-behavior/scripts/claude-guard.mjs +76 -0
  141. package/skills/evaluate-behavior/scripts/guard-rules.mjs +309 -0
  142. package/skills/evaluate-behavior/scripts/lib/agreement.mjs +90 -0
  143. package/skills/evaluate-behavior/scripts/lib/arms.mjs +55 -0
  144. package/skills/evaluate-behavior/scripts/lib/budget.mjs +87 -0
  145. package/skills/evaluate-behavior/scripts/lib/build-source.mjs +287 -0
  146. package/skills/evaluate-behavior/scripts/lib/clear.mjs +74 -0
  147. package/skills/evaluate-behavior/scripts/lib/container.mjs +395 -0
  148. package/skills/evaluate-behavior/scripts/lib/decision.mjs +418 -0
  149. package/skills/evaluate-behavior/scripts/lib/definitions.mjs +1072 -0
  150. package/skills/evaluate-behavior/scripts/lib/freeflow.mjs +103 -0
  151. package/skills/evaluate-behavior/scripts/lib/grade-command.mjs +591 -0
  152. package/skills/evaluate-behavior/scripts/lib/grade-comparison.mjs +90 -0
  153. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-interaction.mjs +19 -18
  154. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-support.mjs +32 -5
  155. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-workspace.mjs +28 -12
  156. package/skills/evaluate-behavior/scripts/lib/grade.mjs +101 -0
  157. package/skills/evaluate-behavior/scripts/lib/hooks.mjs +98 -0
  158. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/confinement.mjs +196 -0
  159. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/constraints.mjs +111 -0
  160. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/index.mjs +48 -0
  161. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/isolation.mjs +74 -0
  162. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/launch.mjs +123 -0
  163. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/model-call.mjs +73 -0
  164. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/recorder.mjs +178 -0
  165. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/session.mjs +494 -0
  166. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/skills.mjs +81 -0
  167. package/skills/evaluate-behavior/scripts/lib/hosts/index.mjs +31 -0
  168. package/skills/evaluate-behavior/scripts/lib/hosts/names.mjs +3 -0
  169. package/skills/evaluate-behavior/scripts/lib/hosts/pi/confinement.mjs +173 -0
  170. package/skills/evaluate-behavior/scripts/lib/hosts/pi/host.mjs +148 -0
  171. package/skills/evaluate-behavior/scripts/lib/hosts/pi/index.mjs +70 -0
  172. package/skills/evaluate-behavior/scripts/lib/hosts/pi/isolation.mjs +81 -0
  173. package/skills/evaluate-behavior/scripts/lib/hosts/pi/model-call.mjs +79 -0
  174. package/skills/evaluate-behavior/scripts/lib/hosts/pi/process.mjs +241 -0
  175. package/skills/{evaluate-skill/scripts/lib → evaluate-behavior/scripts/lib/hosts/pi}/rpc.mjs +144 -26
  176. package/skills/evaluate-behavior/scripts/lib/identity.mjs +82 -0
  177. package/skills/evaluate-behavior/scripts/lib/judge.mjs +688 -0
  178. package/skills/evaluate-behavior/scripts/lib/metrics.mjs +332 -0
  179. package/skills/evaluate-behavior/scripts/lib/model-call.mjs +17 -0
  180. package/skills/evaluate-behavior/scripts/lib/participants.mjs +616 -0
  181. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/process.mjs +22 -0
  182. package/skills/evaluate-behavior/scripts/lib/queue.mjs +54 -0
  183. package/skills/evaluate-behavior/scripts/lib/reference.mjs +343 -0
  184. package/skills/evaluate-behavior/scripts/lib/reuse.mjs +277 -0
  185. package/skills/evaluate-behavior/scripts/lib/review.mjs +933 -0
  186. package/skills/evaluate-behavior/scripts/lib/runner.mjs +732 -0
  187. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/sandbox.mjs +121 -14
  188. package/skills/evaluate-behavior/scripts/lib/scan-shell.mjs +457 -0
  189. package/skills/evaluate-behavior/scripts/lib/scan.mjs +479 -0
  190. package/skills/evaluate-behavior/scripts/lib/seal.mjs +91 -0
  191. package/skills/evaluate-behavior/scripts/lib/shell.mjs +560 -0
  192. package/skills/evaluate-behavior/scripts/lib/source-override.mjs +64 -0
  193. package/skills/evaluate-behavior/scripts/lib/subject-file.mjs +88 -0
  194. package/skills/{evaluate-skill/scripts/lib/pi.mjs → evaluate-behavior/scripts/lib/subject.mjs} +239 -262
  195. package/skills/evaluate-behavior/scripts/lib/task-copy.mjs +124 -0
  196. package/skills/evaluate-behavior/scripts/lib/trials.mjs +524 -0
  197. package/skills/evaluate-behavior/scripts/lib/validity.mjs +68 -0
  198. package/skills/evaluate-behavior/scripts/lib/view-html.mjs +454 -0
  199. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/view.mjs +218 -11
  200. package/skills/evaluate-behavior/scripts/pi-command-tool.mjs +159 -0
  201. package/skills/evaluate-behavior/scripts/pi-container-route.mjs +23 -0
  202. package/skills/evaluate-behavior/scripts/pi-guard.mjs +77 -0
  203. package/skills/evaluate-behavior/scripts/pi-login-refresh.mjs +31 -0
  204. package/skills/evaluate-behavior/scripts/skill-eval.mjs +586 -0
  205. package/skills/execute-work/SKILL.md +96 -72
  206. package/skills/execute-work/references/code-practices.md +27 -49
  207. package/skills/execute-work/references/design.md +271 -0
  208. package/skills/execute-work/references/diagnose.md +117 -0
  209. package/skills/execute-work/references/migration.md +108 -0
  210. package/skills/execute-work/references/simplify.md +65 -0
  211. package/skills/execute-work/scripts/self-review.mjs +422 -0
  212. package/skills/execute-work/scripts/touch-map.mjs +290 -0
  213. package/skills/review-work/SKILL.md +94 -64
  214. package/skills/review-work/references/adjudication.md +94 -0
  215. package/skills/review-work/references/artifact.md +198 -0
  216. package/skills/review-work/references/evals-and-judges.md +66 -0
  217. package/skills/review-work/references/work.md +177 -0
  218. package/skills/review-work/scripts/check-brief.mjs +128 -0
  219. package/skills/review-work/scripts/review-packet.mjs +233 -0
  220. package/skills/setup-freeflow/SKILL.md +69 -16
  221. package/skills/track-work/SKILL.md +135 -151
  222. package/skills/track-work/references/handoff.md +190 -0
  223. package/skills/track-work/references/projects.md +51 -0
  224. package/skills/track-work/references/working-record-format.md +201 -344
  225. package/skills/track-work/scripts/lib/document.mjs +79 -19
  226. package/skills/track-work/scripts/lib/format.mjs +18 -1
  227. package/skills/track-work/scripts/lib/recover.mjs +254 -0
  228. package/skills/track-work/scripts/lib/registry.mjs +656 -0
  229. package/skills/track-work/scripts/lib/search.mjs +40 -0
  230. package/skills/track-work/scripts/lib/store.mjs +53 -21
  231. package/skills/track-work/scripts/lib/transitions.mjs +79 -4
  232. package/skills/track-work/scripts/lib/views.mjs +50 -1
  233. package/skills/track-work/scripts/working-record.mjs +263 -22
  234. package/skills/verify-work/SKILL.md +64 -47
  235. package/skills/verify-work/references/feature-map.md +120 -0
  236. package/skills/verify-work/references/runtime-evidence.md +203 -0
  237. package/skills/verify-work/references/test-design.md +27 -6
  238. package/skills/verify-work/scripts/test-changes.mjs +246 -0
  239. package/skills/write-docs/SKILL.md +171 -0
  240. package/skills/write-docs/references/documentation-shapes.md +184 -0
  241. package/skills/write-docs/references/spec-and-plan-shapes.md +308 -0
  242. package/skills/write-docs/scripts/artifact-check.mjs +148 -0
  243. package/skills/write-docs/scripts/docs-check.mjs +229 -0
  244. package/skills/write-docs/scripts/plan-lint.mjs +123 -0
  245. package/skills/write-skill/SKILL.md +165 -165
  246. package/skills/write-skill/references/activation-and-wording.md +143 -0
  247. package/skills/write-skill/references/placement-and-dependencies.md +154 -0
  248. package/skills/write-skill/scripts/lib/compare.mjs +701 -0
  249. package/skills/write-skill/scripts/lib/similarity.mjs +56 -0
  250. package/skills/write-skill/scripts/lib/skill-author.mjs +197 -3
  251. package/skills/write-skill/scripts/skill-author.mjs +67 -8
  252. package/capabilities/context-virtualization/SKILL.md +0 -103
  253. package/capabilities/conversation-history/SKILL.md +0 -53
  254. package/hooks/tests/check-host-adapters.test.mjs +0 -82
  255. package/hooks/tests/check-runtime-context-hook.sh +0 -212
  256. package/pi-extension/dist/cognitive-routing-v2/projection.js +0 -330
  257. package/pi-extension/dist/cognitive-routing-v2/runtime.js +0 -2181
  258. package/pi-extension/dist/cognitive-routing-v2/tools.js +0 -60
  259. package/pi-extension/dist/context-virtualization/commands.js +0 -89
  260. package/pi-extension/dist/context-virtualization/projector.js +0 -42
  261. package/pi-extension/dist/context-virtualization/runtime.js +0 -378
  262. package/pi-extension/dist/context-virtualization/state.js +0 -57
  263. package/pi-extension/dist/context-virtualization/types.js +0 -10
  264. package/pi-extension/dist/conversation-history/passages.js +0 -66
  265. package/pi-extension/dist/conversation-history/ranking.js +0 -105
  266. package/pi-extension/dist/conversation-history/runtime.js +0 -226
  267. package/pi-extension/dist/conversation-history/search.js +0 -56
  268. package/pi-extension/dist/conversation-history/types.js +0 -1
  269. package/pi-extension/dist/freeflow-context/resolver.js +0 -120
  270. package/pi-extension/dist/freeflow-context/runtime.js +0 -80
  271. package/pi-extension/dist/freeflow-context/source-projector.js +0 -95
  272. package/pi-extension/dist/freeflow-context/tool.js +0 -314
  273. package/pi-extension/dist/freeflow-context/types.js +0 -12
  274. package/pi-extension/dist/freeflow-context/visibility.js +0 -28
  275. package/pi-extension/dist/integrations/mcp-config.js +0 -29
  276. package/pi-extension/dist/runtime/runtime-context.js +0 -754
  277. package/pi-extension/dist/runtime/runtime-identity.js +0 -5
  278. package/pi-extension/dist/session-sources/provenance.js +0 -32
  279. package/pi-extension/dist/settings/settings-ui.js +0 -1360
  280. package/pi-extension/dist/ui/text-component.js +0 -57
  281. package/pi-extension/src/cognitive-routing-v2/budget.ts +0 -42
  282. package/pi-extension/src/cognitive-routing-v2/config.ts +0 -173
  283. package/pi-extension/src/cognitive-routing-v2/projection.ts +0 -375
  284. package/pi-extension/src/cognitive-routing-v2/render.ts +0 -277
  285. package/pi-extension/src/cognitive-routing-v2/runtime.ts +0 -2241
  286. package/pi-extension/src/cognitive-routing-v2/schemas.ts +0 -180
  287. package/pi-extension/src/cognitive-routing-v2/state.ts +0 -839
  288. package/pi-extension/src/cognitive-routing-v2/tools.ts +0 -62
  289. package/pi-extension/src/cognitive-routing-v2/types.ts +0 -254
  290. package/pi-extension/src/context-virtualization/commands.ts +0 -111
  291. package/pi-extension/src/context-virtualization/projector.ts +0 -62
  292. package/pi-extension/src/context-virtualization/runtime.ts +0 -428
  293. package/pi-extension/src/context-virtualization/state.ts +0 -79
  294. package/pi-extension/src/context-virtualization/types.ts +0 -92
  295. package/pi-extension/src/conversation-history/passages.ts +0 -81
  296. package/pi-extension/src/conversation-history/ranking.ts +0 -155
  297. package/pi-extension/src/conversation-history/runtime.ts +0 -250
  298. package/pi-extension/src/conversation-history/search.ts +0 -79
  299. package/pi-extension/src/conversation-history/types.ts +0 -31
  300. package/pi-extension/src/freeflow-context/resolver.ts +0 -139
  301. package/pi-extension/src/freeflow-context/runtime.ts +0 -100
  302. package/pi-extension/src/freeflow-context/source-projector.ts +0 -106
  303. package/pi-extension/src/freeflow-context/tool.ts +0 -366
  304. package/pi-extension/src/freeflow-context/types.ts +0 -70
  305. package/pi-extension/src/freeflow-context/visibility.ts +0 -53
  306. package/pi-extension/src/index.ts +0 -390
  307. package/pi-extension/src/integrations/mcp-config.ts +0 -32
  308. package/pi-extension/src/provider-support/astra/adapter.ts +0 -108
  309. package/pi-extension/src/provider-support/astra/history.ts +0 -145
  310. package/pi-extension/src/provider-support/astra/index.ts +0 -12
  311. package/pi-extension/src/provider-support/astra/session-state.ts +0 -113
  312. package/pi-extension/src/provider-support/index.ts +0 -5
  313. package/pi-extension/src/runtime/request-history.ts +0 -243
  314. package/pi-extension/src/runtime/runtime-context.ts +0 -860
  315. package/pi-extension/src/runtime/runtime-identity.ts +0 -8
  316. package/pi-extension/src/session-sources/events.ts +0 -230
  317. package/pi-extension/src/session-sources/provenance.ts +0 -39
  318. package/pi-extension/src/session-sources/read-only-session.ts +0 -170
  319. package/pi-extension/src/session-sources/sources.ts +0 -334
  320. package/pi-extension/src/settings/settings-tui.ts +0 -501
  321. package/pi-extension/src/settings/settings-ui.ts +0 -1652
  322. package/pi-extension/src/ui/text-component.ts +0 -66
  323. package/pi-extension/tests/cache-reuse/history.test.js +0 -117
  324. package/pi-extension/tests/cache-reuse/native.test.js +0 -91
  325. package/pi-extension/tests/cache-reuse/settings.test.js +0 -211
  326. package/pi-extension/tests/cognitive-routing-v2/communication.test.js +0 -577
  327. package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +0 -183
  328. package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +0 -557
  329. package/pi-extension/tests/cognitive-routing-v2/native.test.js +0 -474
  330. package/pi-extension/tests/cognitive-routing-v2/performance.test.js +0 -87
  331. package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +0 -300
  332. package/pi-extension/tests/cognitive-routing-v2/projection.test.js +0 -241
  333. package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +0 -1034
  334. package/pi-extension/tests/cognitive-routing-v2/render.test.js +0 -244
  335. package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +0 -423
  336. package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +0 -521
  337. package/pi-extension/tests/cognitive-routing-v2/state.test.js +0 -586
  338. package/pi-extension/tests/context-virtualization/extension.test.js +0 -775
  339. package/pi-extension/tests/context-virtualization/projector.test.js +0 -110
  340. package/pi-extension/tests/context-virtualization/runtime.test.js +0 -230
  341. package/pi-extension/tests/conversation-history/runtime.test.js +0 -98
  342. package/pi-extension/tests/conversation-history/search.test.js +0 -97
  343. package/pi-extension/tests/fixtures/pi-host.js +0 -4
  344. package/pi-extension/tests/fixtures/routing-native.js +0 -191
  345. package/pi-extension/tests/integration/mode-free-core.test.js +0 -220
  346. package/pi-extension/tests/integration/pi-extension.test.js +0 -1447
  347. package/pi-extension/tests/integration/prompt-architecture.test.js +0 -447
  348. package/pi-extension/tests/integration/unaffected-regressions.test.js +0 -478
  349. package/pi-extension/tests/provider-support/astra-boundaries.test.js +0 -75
  350. package/pi-extension/tests/provider-support/astra.test.js +0 -306
  351. package/pi-extension/tests/provider-support/cli.test.js +0 -92
  352. package/pi-extension/tests/provider-support/native.test.js +0 -183
  353. package/pi-extension/tests/settings/settings-tui.test.js +0 -243
  354. package/pi-extension/tsconfig.json +0 -16
  355. package/plugin.json +0 -33
  356. package/runtime/prompts/context-virtualization.md +0 -3
  357. package/runtime/prompts/conversation-history.md +0 -3
  358. package/skills/action-selection/SKILL.md +0 -100
  359. package/skills/action-selection/references/trajectory-stalls.md +0 -71
  360. package/skills/bypass/SKILL.md +0 -153
  361. package/skills/commit-work/SKILL.md +0 -145
  362. package/skills/commit-work/references/git-state-edges.md +0 -94
  363. package/skills/commit-work/references/simple-push.md +0 -92
  364. package/skills/commit-work/references/staging-decisions.md +0 -106
  365. package/skills/decision-gate/SKILL.md +0 -106
  366. package/skills/design-for-depth/SKILL.md +0 -117
  367. package/skills/design-for-depth/references/design-pressure-signals.md +0 -182
  368. package/skills/design-for-depth/references/implementation-decisions.md +0 -76
  369. package/skills/design-for-depth/references/interface-design-loop.md +0 -136
  370. package/skills/design-for-depth/references/module-and-dependency-design.md +0 -147
  371. package/skills/design-for-depth/references/software-design-philosophy.md +0 -202
  372. package/skills/design-for-depth/references/state-and-failure-boundaries.md +0 -136
  373. package/skills/diagnose-failure/SKILL.md +0 -125
  374. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +0 -48
  375. package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +0 -51
  376. package/skills/discuss/SKILL.md +0 -116
  377. package/skills/evaluate-skill/SKILL.md +0 -219
  378. package/skills/evaluate-skill/references/evaluation-definition-schema.md +0 -385
  379. package/skills/evaluate-skill/references/evaluation-design.md +0 -112
  380. package/skills/evaluate-skill/references/execution-and-evidence.md +0 -90
  381. package/skills/evaluate-skill/references/review-and-revision.md +0 -92
  382. package/skills/evaluate-skill/scripts/lib/definitions.mjs +0 -407
  383. package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +0 -60
  384. package/skills/evaluate-skill/scripts/lib/grade.mjs +0 -64
  385. package/skills/evaluate-skill/scripts/lib/runner.mjs +0 -368
  386. package/skills/evaluate-skill/scripts/pi-guard.mjs +0 -164
  387. package/skills/evaluate-skill/scripts/skill-eval.mjs +0 -102
  388. package/skills/execute-work/references/execute-work-edges.md +0 -68
  389. package/skills/finish-branch/SKILL.md +0 -117
  390. package/skills/finish-branch/references/integration-options.md +0 -80
  391. package/skills/handoff/SKILL.md +0 -82
  392. package/skills/handoff/references/handoff-templates.md +0 -150
  393. package/skills/launch-work/SKILL.md +0 -116
  394. package/skills/launch-work/references/launch-readiness.md +0 -85
  395. package/skills/migration-work/SKILL.md +0 -115
  396. package/skills/migration-work/references/migration-lifecycle.md +0 -82
  397. package/skills/release-work/SKILL.md +0 -118
  398. package/skills/release-work/references/release-evidence.md +0 -78
  399. package/skills/review-artifact/SKILL.md +0 -142
  400. package/skills/review-artifact/references/adjudicate-artifact-review.md +0 -101
  401. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +0 -159
  402. package/skills/review-work/references/adjudicate-work-review.md +0 -97
  403. package/skills/review-work/references/independent-work-reviewer-contract.md +0 -139
  404. package/skills/review-work/references/security-risk-lens.md +0 -69
  405. package/skills/setup-freeflow/references/activation-contract.md +0 -109
  406. package/skills/setup-freeflow/references/host-setup.md +0 -67
  407. package/skills/simplify-code/SKILL.md +0 -85
  408. package/skills/simplify-code/references/simplification-patterns.md +0 -70
  409. package/skills/verify-work/references/browser-runtime-evidence.md +0 -55
  410. package/skills/verify-work/references/integration-evidence.md +0 -47
  411. package/skills/verify-work/references/performance-evidence.md +0 -57
  412. package/skills/workflow/SKILL.md +0 -127
  413. package/skills/workflow/references/domain-skill-composition.md +0 -43
  414. package/skills/write-plan/SKILL.md +0 -92
  415. package/skills/write-plan/references/plan-shapes.md +0 -156
  416. package/skills/write-skill/references/activation-boundaries.md +0 -104
  417. package/skills/write-skill/references/agent-first-instructions.md +0 -121
  418. package/skills/write-skill/references/progressive-disclosure.md +0 -127
  419. package/skills/write-skill/references/skill-dependency-graphs.md +0 -190
  420. package/skills/write-spec/SKILL.md +0 -92
  421. package/skills/write-spec/references/artifact-standards.md +0 -86
  422. package/skills/write-spec/references/decision-records.md +0 -78
  423. package/skills/write-spec/references/spec-shapes.md +0 -143
  424. /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/budget.js +0 -0
  425. /package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/evidence.mjs +0 -0
  426. /package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-observer.mjs +0 -0
@@ -0,0 +1,68 @@
1
+ // The validity gate: a subject run the host reported complete is graded only when it shows a model actually ran.
2
+ // A login that failed, a provider that answered nothing, or a host that exited cleanly without calling the model
3
+ // would otherwise be graded like real behavior: every check fails, or an "absent" check passes, and the run counts
4
+ // in a comparison. Such a run becomes `invalid` with its reasons, before any grader runs; it is never a fail, never
5
+ // counted in a comparison or decision, and it stops a pilot. An unclean host exit is already `infrastructure-failed`.
6
+ //
7
+ // Cost is not the signal: a model with no configured price reports zero cost for real work. Tokens are: every real
8
+ // model call has input and output tokens, so a run whose usage totals zero tokens did not reach a model. A provider
9
+ // that reports no token usage at all cannot be told apart from one that never answered, so its runs are invalid too.
10
+ //
11
+ // Tool use is not required. A model that answers in one turn without tools, such as a description run whose target
12
+ // did not activate, or a subject that declines the task, is behavior to grade, not a hollow run. A run must leave an
13
+ // answer or written work: one that only read and ended silently has nothing to grade.
14
+
15
+ /** The run's assistant messages, from its transcript (every host records them there). */
16
+ function assistantMessages(run) {
17
+ return (Array.isArray(run.transcript) ? run.transcript : []).filter((message) => message?.role === "assistant");
18
+ }
19
+
20
+ function totalTokens(usage) {
21
+ if (usage === null || typeof usage !== "object") return 0;
22
+ return ["input", "output", "cacheRead", "cacheWrite"].reduce(
23
+ (total, key) => total + (Number.isFinite(usage[key]) ? usage[key] : 0),
24
+ 0,
25
+ );
26
+ }
27
+
28
+ function answered(run) {
29
+ if (typeof run.response === "string" && run.response.trim() !== "") return true;
30
+ return (Array.isArray(run.turns) ? run.turns : []).some(
31
+ (turn) => typeof turn?.response === "string" && turn.response.trim() !== "",
32
+ );
33
+ }
34
+
35
+ function wroteSomething(run) {
36
+ const changes = run.effects?.changes;
37
+ return ["created", "modified", "deleted"].some((key) => Array.isArray(changes?.[key]) && changes[key].length > 0);
38
+ }
39
+
40
+ /**
41
+ * Why a run the host reported complete is not valid evidence, as a list of reasons; empty when it is valid. Only a
42
+ * `complete` run is checked: every other state already says why it is not graded.
43
+ *
44
+ * @param {any} run
45
+ * @returns {string[]}
46
+ */
47
+ export function validityProblems(run) {
48
+ if (run?.state !== "complete") return [];
49
+ const problems = [];
50
+ if (assistantMessages(run).length === 0) problems.push("no model turn: the host recorded no assistant message");
51
+ if (totalTokens(run.usage) === 0) {
52
+ problems.push("no tokens: the run's usage totals zero tokens, so no model call is shown to have happened");
53
+ }
54
+ if (!answered(run) && !wroteSomething(run)) problems.push("no answer and nothing written in the workspace");
55
+ return problems;
56
+ }
57
+
58
+ /**
59
+ * Marks a hollow complete run `invalid` in place, keeping everything it recorded; returns whether it did. The
60
+ * reasons are in `error.reasons`, and `error.kind` is `validity`.
61
+ */
62
+ export function applyValidityGate(run) {
63
+ const problems = validityProblems(run);
64
+ if (problems.length === 0) return false;
65
+ run.state = "invalid";
66
+ run.error = { kind: "validity", message: `not valid evidence: ${problems.join("; ")}`, reasons: problems };
67
+ return true;
68
+ }
@@ -0,0 +1,454 @@
1
+ import { readFile, stat, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { storedArms } from "./arms.mjs";
5
+ import { claimSummary, trialCounts, verdictText } from "./decision.mjs";
6
+ import { readSubjectFile, skippedNote } from "./subject-file.mjs";
7
+ import { resolveResult } from "./view.mjs";
8
+
9
+ // Run content (responses, changed files, tool arguments) can be large or hostile; every value passes through esc().
10
+ const CONTENT_CAP = 20000;
11
+ const VALUE_CAP = 500;
12
+
13
+ /**
14
+ * Writes one self-contained HTML page for a stored result or aggregate: inline CSS, no scripts, no network.
15
+ * Returns the absolute path written. Selectors are refused because the page always covers the whole result.
16
+ */
17
+ export async function writeHtml(
18
+ target,
19
+ file,
20
+ { root = process.cwd(), selectors = { group: null, variant: null }, results = null } = {},
21
+ ) {
22
+ if (selectors.group !== null || selectors.variant !== null) {
23
+ throw new Error("view --html renders the whole result; drop --group and --variant");
24
+ }
25
+ const html = await renderHtml(target, { root, results });
26
+ const destination = path.resolve(root, file);
27
+ await writeFile(destination, html);
28
+ return destination;
29
+ }
30
+
31
+ export async function renderHtml(target, { root = process.cwd(), results = null } = {}) {
32
+ const resultDirectory = await resolveResult(target, root, results);
33
+ const aggregate = await readOptionalJson(path.join(resultDirectory, "aggregate.json"));
34
+ if (aggregate !== null) {
35
+ const parts = [
36
+ claimSection(aggregate),
37
+ decisionBlock(aggregate),
38
+ ...(Array.isArray(aggregate.groups) ? aggregate.groups : []).map(metricsGroupBlock),
39
+ `<p class="meta">Aggregate ${esc(aggregate.id)} · state ${esc(aggregate.state)} · trials ${esc(trialCounts(aggregate))}</p>`,
40
+ ];
41
+ for (const trial of aggregate.trials) {
42
+ parts.push(`<section class="trial"><h2>Trial ${esc(trial.id)} [${esc(trial.state)}]</h2>`);
43
+ try {
44
+ // An aggregate's trials are stored beside it.
45
+ const trialDirectory = await resolveResult(trial.id, root, path.dirname(resultDirectory));
46
+ const summary = await readJson(path.join(trialDirectory, "summary.json"), `trial ${trial.id} summary`);
47
+ parts.push(await resultBody(trialDirectory, summary));
48
+ } catch (error) {
49
+ parts.push(
50
+ `<p class="missing">Trial result unavailable: ${esc(error instanceof Error ? error.message : String(error))}</p>`,
51
+ );
52
+ }
53
+ parts.push("</section>");
54
+ }
55
+ return page(`Aggregate ${aggregate.id}`, parts.join("\n"));
56
+ }
57
+ const summary = await readJson(path.join(resultDirectory, "summary.json"), "result summary");
58
+ return page(`Result ${summary.id}`, await resultBody(resultDirectory, summary));
59
+ }
60
+
61
+ async function resultBody(resultDirectory, summary) {
62
+ const parts = [`<p class="meta">Result ${esc(summary.id)} · state ${esc(summary.state)}</p>`];
63
+ for (const group of Array.isArray(summary.groups) ? summary.groups : []) {
64
+ parts.push(await groupSection(resultDirectory, group));
65
+ }
66
+ return parts.join("\n");
67
+ }
68
+
69
+ async function groupSection(resultDirectory, group) {
70
+ const groupDirectory = path.join(resultDirectory, "groups", group.id);
71
+ const definition = await readJson(path.join(groupDirectory, "definition.json"), `definition for ${group.id}`);
72
+ const grade = await readJson(
73
+ path.join(groupDirectory, group.artifacts?.grade ?? "deterministic-grade.json"),
74
+ `grade for ${group.id}`,
75
+ );
76
+ const parts = [
77
+ `<section class="group"><h2>Group ${esc(group.id)} [${esc(group.state)}] <span class="muted">type=${esc(definition.type)}</span></h2>`,
78
+ promptBlock(definition),
79
+ ];
80
+ const reviewQuestions = Array.isArray(definition.review_questions) ? definition.review_questions : [];
81
+ if (reviewQuestions.length > 0) {
82
+ parts.push(
83
+ `<h3>Review questions</h3><ul>${reviewQuestions.map((question) => `<li>${esc(question)}</li>`).join("")}</ul>`,
84
+ );
85
+ }
86
+ for (const arm of storedArms(group, definition)) {
87
+ parts.push(await armSection(groupDirectory, arm, grade));
88
+ }
89
+ const advisory = await readOptionalJson(path.join(groupDirectory, "semantic-grade.json"));
90
+ if (advisory !== null) parts.push(advisoryBlock(advisory));
91
+ parts.push("</section>");
92
+ return parts.join("\n");
93
+ }
94
+
95
+ function promptBlock(definition) {
96
+ if (typeof definition.input?.prompt === "string") {
97
+ return `<h3>Prompt</h3><pre>${esc(definition.input.prompt)}</pre>`;
98
+ }
99
+ const turns = Array.isArray(definition.input?.turns) ? definition.input.turns : [];
100
+ return turns.map((turn, index) => `<h3>Turn ${index + 1} prompt</h3><pre>${esc(turn)}</pre>`).join("\n");
101
+ }
102
+
103
+ async function armSection(groupDirectory, arm, grade) {
104
+ const variantDirectory = path.join(groupDirectory, arm);
105
+ const run = await readJson(path.join(variantDirectory, "run.json"), `${arm} run`);
106
+ const parts = [`<article class="arm"><h3>${esc(arm)} <span class="muted">[${esc(run.state)}]</span></h3>`];
107
+
108
+ const finalFile = path.resolve(
109
+ variantDirectory,
110
+ typeof run.artifacts?.final === "string" ? run.artifacts.final : "final.md",
111
+ );
112
+ const finalText = await readText(finalFile);
113
+ parts.push(
114
+ `<h4>Final response</h4>${finalText === null ? '<p class="missing">No final response recorded.</p>' : preBlock(finalText)}`,
115
+ );
116
+
117
+ parts.push(await changedFilesBlock(run, variantDirectory));
118
+ parts.push(toolCallsBlock(run));
119
+ parts.push(checksBlock(grade, arm));
120
+ if (run.metrics && typeof run.metrics === "object") parts.push(metricsBlock(run.metrics));
121
+ const judged = await readOptionalJson(path.join(variantDirectory, "judged-grade.json"));
122
+ if (judged !== null) parts.push(judgedBlock(judged));
123
+
124
+ parts.push("</article>");
125
+ return parts.join("\n");
126
+ }
127
+
128
+ async function changedFilesBlock(run, variantDirectory) {
129
+ const changes = run.effects?.changes;
130
+ if (!changes) return "";
131
+ const workspace = typeof run.workspace === "string" ? path.resolve(variantDirectory, run.workspace) : null;
132
+ const entries = [];
133
+ for (const kind of ["created", "modified", "deleted"]) {
134
+ for (const relative of Array.isArray(changes[kind]) ? changes[kind] : []) {
135
+ entries.push(await changedFileEntry(kind, String(relative), workspace));
136
+ }
137
+ }
138
+ if (entries.length === 0) return "<h4>Changed files</h4><p>None.</p>";
139
+ return `<h4>Changed files</h4>${entries.join("\n")}`;
140
+ }
141
+
142
+ async function changedFileEntry(kind, relative, workspace) {
143
+ const label = `${esc(kind)} ${esc(relative)}`;
144
+ if (kind === "deleted")
145
+ return `<details><summary>${label}</summary><p class="missing">Deleted; no content.</p></details>`;
146
+ if (workspace === null)
147
+ return `<details><summary>${label}</summary><p class="missing">Content unavailable.</p></details>`;
148
+ const file = path.resolve(workspace, relative);
149
+ if (!file.startsWith(`${workspace}${path.sep}`)) {
150
+ return `<details><summary>${label}</summary><p class="missing">Path leaves the workspace; not shown.</p></details>`;
151
+ }
152
+ // Never through a link the run made, and only a regular file inside the workspace, read to a bound.
153
+ const read = await readSubjectFile(workspace, relative, { limit: CONTENT_CAP * 4 });
154
+ if (read.skipped !== undefined) {
155
+ const why =
156
+ read.skipped === "missing" || read.skipped === "binary" ? "Content unavailable." : `${skippedNote(read)}.`;
157
+ return `<details><summary>${label}</summary><p class="missing">${esc(why)}</p></details>`;
158
+ }
159
+ const { text } = read;
160
+ const cut = read.truncated || text.length > CONTENT_CAP;
161
+ const shown = text.length > CONTENT_CAP ? text.slice(0, CONTENT_CAP) : text;
162
+ const of = read.truncated ? `${read.size} bytes` : `${text.length} characters`;
163
+ const note = cut ? `<p class="missing">Cut at ${CONTENT_CAP} of ${of}.</p>` : "";
164
+ return `<details><summary>${label}</summary>${preBlock(shown)}${note}</details>`;
165
+ }
166
+
167
+ function toolCallsBlock(run) {
168
+ const calls = Array.isArray(run.turns)
169
+ ? run.turns.flatMap((turn) => (turn.toolActivity ?? []).map((entry) => ({ turn: turn.turn, entry })))
170
+ : (run.toolActivity ?? []).map((entry) => ({ turn: null, entry }));
171
+ if (calls.length === 0) return "<h4>Tool calls</h4><p>None.</p>";
172
+ const rows = calls.map(({ turn, entry }) => {
173
+ const where = turn === null ? "" : `turn ${esc(turn)} · `;
174
+ const failed = entry.isError === true ? ' <span class="fail">error</span>' : "";
175
+ return `<li>${where}<code>${esc(entry.toolName ?? "unknown")}</code>${failed} <code>${esc(compact(entry.args))}</code></li>`;
176
+ });
177
+ return `<h4>Tool calls</h4><ol>${rows.join("")}</ol>`;
178
+ }
179
+
180
+ function checksBlock(grade, arm) {
181
+ const checks = Array.isArray(grade.checks) ? grade.checks.filter((check) => check.variant === arm) : [];
182
+ if (checks.length === 0) return "<h4>Deterministic checks</h4><p>None for this arm.</p>";
183
+ const rows = checks.map(
184
+ (check) =>
185
+ `<tr><td>${esc(check.id)}</td><td>${esc(check.kind)}</td><td class="${check.state === "pass" ? "pass" : check.state === "fail" ? "fail" : ""}">${esc(check.state)}</td><td><code>${esc(compact(check.expected))}</code></td><td><code>${esc(compact(check.observed))}</code></td></tr>`,
186
+ );
187
+ return `<h4>Deterministic checks</h4><table><thead><tr><th>id</th><th>kind</th><th>state</th><th>expected</th><th>observed</th></tr></thead><tbody>${rows.join("")}</tbody></table>`;
188
+ }
189
+
190
+ function metricsBlock(metrics) {
191
+ const rows = Object.entries(metrics).map(
192
+ ([name, value]) => `<tr><td>${esc(name)}</td><td><code>${esc(compact(value))}</code></td></tr>`,
193
+ );
194
+ return `<h4>Metrics</h4><table><tbody>${rows.join("")}</tbody></table>`;
195
+ }
196
+
197
+ // The judged-grade.json shape is written by review.mjs (rubric judging) and read by judge.mjs (judgedLines).
198
+ function judgedBlock(judged) {
199
+ const dimensions = Array.isArray(judged.rubric?.dimensions) ? judged.rubric.dimensions : [];
200
+ const combined = Array.isArray(judged.answers) ? judged.answers : [];
201
+ const judges = Array.isArray(judged.judges) ? judged.judges : [];
202
+ const gaps = Array.isArray(judged.contractGaps) ? judged.contractGaps : [];
203
+ const parts = [
204
+ `<h4>Judged evidence <span class="muted">(judged, not deterministic grades)</span></h4>`,
205
+ `<p class="meta">state ${esc(judged.state)} · combine ${esc(judged.combine ?? "majority")} · truncated ${esc(judged.truncated ?? 0)}</p>`,
206
+ gaps.length === 0
207
+ ? "<p>Contract gaps: none</p>"
208
+ : `<p class="fail">Contract gaps: ${gaps.map((gap) => esc(gap)).join("; ")}</p>`,
209
+ ];
210
+ for (const dimension of dimensions) {
211
+ const result = combined.find((entry) => entry.dimension === dimension.id);
212
+ const rows = judges.map((judge) => {
213
+ const answer = (judge.answers ?? []).find((entry) => entry.dimension === dimension.id);
214
+ return `<tr><td>${esc(judgeLabel(judge))}<br><span class="muted">family ${esc(judge.familyRelation ?? "unknown")} · ${esc(judge.state)}</span></td><td>${esc(answer?.answer ?? "-")}</td><td>${esc(answer?.evidence ?? "-")}</td><td>${calibrationCell(judge.calibration, dimension.id)}</td></tr>`;
215
+ });
216
+ const votes = Array.isArray(result?.votes) ? result.votes.map((vote) => esc(vote)).join(", ") : "-";
217
+ rows.push(
218
+ `<tr><th>combined</th><td>${esc(result?.answer ?? "-")}</td><td>votes ${votes || "-"}</td><td></td></tr>`,
219
+ );
220
+ parts.push(
221
+ `<h5>${esc(dimension.id)} <span class="muted">${esc(dimension.question ?? "")}</span></h5>`,
222
+ `<table><thead><tr><th>judge</th><th>answer</th><th>evidence</th><th>calibration</th></tr></thead><tbody>${rows.join("")}</tbody></table>`,
223
+ );
224
+ }
225
+ for (const judge of judges) {
226
+ for (const error of judge.errors ?? []) parts.push(`<p class="fail">${esc(judgeLabel(judge))}: ${esc(error)}</p>`);
227
+ }
228
+ return parts.join("\n");
229
+ }
230
+
231
+ function judgeLabel(judge) {
232
+ return `${judge.model ?? "unknown"}${judge.thinking ? ` (${judge.thinking})` : ""}`;
233
+ }
234
+
235
+ function calibrationCell(calibration, dimensionId) {
236
+ if (calibration?.state !== "checked") return "not checked";
237
+ const measured = calibration.dimensions?.[dimensionId];
238
+ const kappa = measured ? `kappa ${fmt(measured.kappa)} over ${esc(measured.items ?? "-")} item(s)` : "no kappa";
239
+ return `agreement ${fmt(calibration.agreement)} over ${esc(calibration.runs ?? 0)} labelled run(s); ${kappa}; checked ${esc(calibration.checkedAt ?? "-")}`;
240
+ }
241
+
242
+ // The advisory pairwise review (semantic-grade.json). Its answers are not canonical evidence.
243
+ function advisoryBlock(review) {
244
+ const labels = review.labels && typeof review.labels === "object" ? review.labels : {};
245
+ const names = Object.keys(labels);
246
+ const arms = names.map((label) => labels[label]);
247
+ const answers = Array.isArray(review.answers) ? review.answers : [];
248
+ const rows = answers.map(
249
+ (answer, index) =>
250
+ `<tr><td>${index + 1}. ${esc(answer.question ?? "")}</td>${arms.map((arm) => `<td>${esc(answer[arm] ?? "-")}</td>`).join("")}<td>${esc(answer.rationale ?? "")}</td></tr>`,
251
+ );
252
+ const parts = [
253
+ `<section class="advisory"><h3>Advisory pairwise review <span class="muted">(advisory, not canonical evidence)</span></h3>`,
254
+ `<p class="meta">state ${esc(review.state)} · model ${esc(review.model ?? "unknown")}${review.thinking ? ` (${esc(review.thinking)})` : ""} · judge family ${esc(review.judge?.family ?? "unknown")} · subject ${esc(review.subject?.familyRelation ?? "unknown")}</p>`,
255
+ `<p class="meta">Labels: ${names.map((label) => `${esc(label)} = ${esc(labels[label])}`).join(", ") || "none"}</p>`,
256
+ `<table><thead><tr><th>question</th>${arms.map((arm) => `<th>${esc(arm)}</th>`).join("")}<th>rationale</th></tr></thead><tbody>${rows.join("")}</tbody></table>`,
257
+ ];
258
+ const agreement = review.swap?.agreement;
259
+ if (agreement) {
260
+ const perArm = agreement.arms
261
+ ? ` · per arm ${Object.entries(agreement.arms)
262
+ .map(([arm, counts]) => `${esc(arm)} ${esc(counts.agreed)}/${esc(counts.questions)}`)
263
+ .join(", ")}`
264
+ : "";
265
+ parts.push(`<p>Order swap agreed on ${esc(agreement.agreed)}/${esc(agreement.questions)}${perArm}</p>`);
266
+ } else if (review.swap === undefined) {
267
+ parts.push(`<p class="missing">Order not swapped.</p>`);
268
+ }
269
+ for (const gap of Array.isArray(review.contractGaps) ? review.contractGaps : []) {
270
+ parts.push(`<p class="fail">Contract gap: ${esc(gap)}</p>`);
271
+ }
272
+ for (const error of Array.isArray(review.errors) ? review.errors : []) {
273
+ parts.push(`<p class="fail">Error: ${esc(error)}</p>`);
274
+ }
275
+ parts.push("</section>");
276
+ return parts.join("\n");
277
+ }
278
+
279
+ // The aggregate's decision: the rule, the split, the sign test p and the verdict.
280
+ function decisionBlock(aggregate) {
281
+ const decision = aggregate.decision;
282
+ if (!decision || typeof decision !== "object" || !decision.rule) return "";
283
+ const rule = decision.rule;
284
+ const measure = Object.entries(rule.measure ?? {})
285
+ .map(([kind, name]) => `${kind} ${name}`)
286
+ .join(", ");
287
+ const rows = [
288
+ ["measure", measure],
289
+ ["direction", `${rule.direction} is better`],
290
+ ["arms", `${decision.arm} against ${decision.reference}`],
291
+ ["method", `${rule.method} (alpha ${fmt(rule.alpha)}, min cases ${rule.min_cases})`],
292
+ ...(rule.trials ? [["trials", `${rule.trials.initial}..${rule.trials.max} step ${rule.trials.step}`]] : []),
293
+ ["rule sha256", decision.ruleSha256],
294
+ ["split (better / worse / ties)", `${decision.better} / ${decision.worse} / ${decision.ties}`],
295
+ ["decided / excluded", `${decision.decided} / ${decision.excluded}`],
296
+ ["p (sign test)", Number.isFinite(decision.p) ? String(Number(decision.p.toPrecision(4))) : "-"],
297
+ ["verdict", verdictText(decision.verdict)],
298
+ ["claim", claimSummary(aggregate)?.reached ?? "none"],
299
+ ];
300
+ const cases = Array.isArray(decision.cases) ? decision.cases : [];
301
+ const caseRows = cases.map(
302
+ (entry) =>
303
+ `<tr><td>${esc(entry.id)}</td><td>${esc(entry.trials ?? "-")}</td><td>${esc(entry.sign ?? "-")}</td><td>${esc(entry.reason ?? "")}</td><td><code>${esc(compact(entry.arms))}</code></td></tr>`,
304
+ );
305
+ return [
306
+ `<section class="decision"><h2>Decision</h2>`,
307
+ `<table><tbody>${rows.map(([name, value]) => `<tr><th>${esc(name)}</th><td>${esc(value)}</td></tr>`).join("")}</tbody></table>`,
308
+ `<h4>Cases</h4><table><thead><tr><th>case</th><th>trials</th><th>sign</th><th>reason</th><th>arms</th></tr></thead><tbody>${caseRows.join("")}</tbody></table>`,
309
+ "</section>",
310
+ ].join("\n");
311
+ }
312
+
313
+ // The per-group metrics section of an aggregate: per arm medians, and paired differences against the reference.
314
+ function metricsGroupBlock(group) {
315
+ const section = group?.metrics;
316
+ if (!section || typeof section !== "object") return "";
317
+ const head = `<section class="metrics"><h3>Metrics: ${esc(group.id)}</h3>`;
318
+ if (typeof section.error === "string") return `${head}<p class="fail">${esc(section.error)}</p></section>`;
319
+ const arms = Object.entries(section.arms ?? {});
320
+ const names = [...new Set(arms.flatMap(([, metrics]) => Object.keys(metrics ?? {})))].filter((name) =>
321
+ arms.some(([, metrics]) => (metrics?.[name]?.count ?? 0) > 0),
322
+ );
323
+ const rows = names.map(
324
+ (name) =>
325
+ `<tr><td>${esc(name)}</td>${arms
326
+ .map(([, metrics]) => {
327
+ const summary = metrics?.[name];
328
+ return `<td>median ${fmt(summary?.median)} · mean ${fmt(summary?.mean)} · n ${esc(summary?.count ?? 0)}</td>`;
329
+ })
330
+ .join("")}</tr>`,
331
+ );
332
+ const diffRows = [];
333
+ for (const [arm, byName] of Object.entries(section.differences ?? {})) {
334
+ for (const name of names) {
335
+ const difference = byName?.[name];
336
+ if (!difference || difference.pairs === 0) continue;
337
+ diffRows.push(
338
+ `<tr><td>${esc(name)}</td><td>${esc(arm)} − ${esc(section.reference)}</td><td>mean ${fmt(difference.mean)} · median ${fmt(difference.median)} · pairs ${esc(difference.pairs)}</td></tr>`,
339
+ );
340
+ }
341
+ }
342
+ const parts = [head];
343
+ parts.push(
344
+ `<table><thead><tr><th>metric</th>${arms.map(([arm]) => `<th>${esc(arm)}</th>`).join("")}</tr></thead><tbody>${rows.join("")}</tbody></table>`,
345
+ );
346
+ if (diffRows.length > 0) {
347
+ parts.push(
348
+ `<h4>Paired differences</h4><table><thead><tr><th>metric</th><th>comparison</th><th>difference</th></tr></thead><tbody>${diffRows.join("")}</tbody></table>`,
349
+ );
350
+ }
351
+ parts.push("</section>");
352
+ return parts.join("\n");
353
+ }
354
+
355
+ function fmt(value) {
356
+ if (value === null || value === undefined) return "-";
357
+ if (typeof value === "number") return Number.isFinite(value) ? String(Number(value.toFixed(3))) : "-";
358
+ return esc(value);
359
+ }
360
+
361
+ // Worded by decision.mjs, as in the text view, so a decision's verdict is never shown as "none".
362
+ function claimSection(aggregate) {
363
+ const summary = claimSummary(aggregate);
364
+ if (summary === null) return "";
365
+ return `<section class="claim"><h2>Claim</h2><p>${esc(summary.reached)}</p><p class="muted">${esc(summary.detail)}</p></section>`;
366
+ }
367
+
368
+ function preBlock(text) {
369
+ const value = String(text);
370
+ const cut = value.length > CONTENT_CAP;
371
+ return `<pre>${esc(cut ? value.slice(0, CONTENT_CAP) : value)}</pre>${cut ? `<p class="missing">Cut at ${CONTENT_CAP} of ${value.length} characters.</p>` : ""}`;
372
+ }
373
+
374
+ function compact(value) {
375
+ if (value === undefined) return "-";
376
+ const text = typeof value === "string" ? value : (JSON.stringify(value) ?? "-");
377
+ return text.length > VALUE_CAP ? `${text.slice(0, VALUE_CAP)}... (cut at ${VALUE_CAP} of ${text.length})` : text;
378
+ }
379
+
380
+ function esc(value) {
381
+ return String(value)
382
+ .replace(/&/g, "&amp;")
383
+ .replace(/</g, "&lt;")
384
+ .replace(/>/g, "&gt;")
385
+ .replace(/"/g, "&quot;")
386
+ .replace(/'/g, "&#39;");
387
+ }
388
+
389
+ function page(title, body) {
390
+ return `<!doctype html>
391
+ <html lang="en">
392
+ <head>
393
+ <meta charset="utf-8">
394
+ <meta name="viewport" content="width=device-width, initial-scale=1">
395
+ <title>${esc(title)}</title>
396
+ <style>
397
+ :root { color-scheme: light dark; --bg: #ffffff; --fg: #1d1f23; --muted: #5c6370; --border: #d8dce3; --code: #f5f6f8; --pass: #1a7f37; --fail: #cf222e; }
398
+ @media (prefers-color-scheme: dark) {
399
+ :root:not([data-theme="light"]) { --bg: #0f1115; --fg: #e6e8eb; --muted: #9aa3ad; --border: #2c313a; --code: #171a20; --pass: #3fb950; --fail: #ff7b72; }
400
+ }
401
+ :root[data-theme="dark"] { --bg: #0f1115; --fg: #e6e8eb; --muted: #9aa3ad; --border: #2c313a; --code: #171a20; --pass: #3fb950; --fail: #ff7b72; }
402
+ body { margin: 0; background: var(--bg); color: var(--fg); font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; }
403
+ main { max-width: 960px; margin: 0 auto; padding: 16px; }
404
+ h1 { font-size: 20px; }
405
+ h2 { font-size: 18px; margin: 0 0 8px; }
406
+ h3 { font-size: 16px; margin: 16px 0 6px; }
407
+ h4 { font-size: 14px; margin: 14px 0 4px; }
408
+ h5 { font-size: 14px; margin: 12px 0 4px; }
409
+ section, article { border-top: 1px solid var(--border); padding-top: 8px; margin-top: 16px; }
410
+ .muted, .meta { color: var(--muted); font-size: 13px; }
411
+ .claim { border-top: 0; }
412
+ pre { background: var(--code); border: 1px solid var(--border); border-radius: 6px; padding: 8px; font-size: 13px; white-space: pre-wrap; overflow-wrap: anywhere; margin: 6px 0; }
413
+ code { font-size: 13px; overflow-wrap: anywhere; }
414
+ table { width: 100%; border-collapse: collapse; font-size: 13px; }
415
+ th, td { border-bottom: 1px solid var(--border); padding: 4px 6px; text-align: left; vertical-align: top; overflow-wrap: anywhere; }
416
+ details { margin: 6px 0; }
417
+ summary { cursor: pointer; font-family: ui-monospace, Menlo, monospace; font-size: 13px; overflow-wrap: anywhere; }
418
+ .pass { color: var(--pass); }
419
+ .fail { color: var(--fail); }
420
+ .missing { color: var(--muted); font-style: italic; }
421
+ </style>
422
+ </head>
423
+ <body>
424
+ <main>
425
+ ${body}
426
+ </main>
427
+ </body>
428
+ </html>
429
+ `;
430
+ }
431
+
432
+ async function readText(file) {
433
+ if (!(await stat(file).catch(() => null))) return null;
434
+ return readFile(file, "utf8");
435
+ }
436
+
437
+ async function readOptionalJson(file) {
438
+ if (!(await stat(file).catch(() => null))) return null;
439
+ return readJson(file, path.basename(file));
440
+ }
441
+
442
+ async function readJson(file, label) {
443
+ let contents;
444
+ try {
445
+ contents = await readFile(file, "utf8");
446
+ } catch {
447
+ throw new Error(`Cannot read ${label}: ${file}`);
448
+ }
449
+ try {
450
+ return JSON.parse(contents);
451
+ } catch {
452
+ throw new Error(`${label} is not valid JSON: ${file}`);
453
+ }
454
+ }