@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,90 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+
3
+ import { DEFAULT_ARMS, DEFAULT_REFERENCE, isClassicPair } from "./arms.mjs";
4
+ import { hasOwn } from "./grade-support.mjs";
5
+
6
+ /**
7
+ * A comparison ID names exactly one expectation per arm, all of one kind and expected value. Each non-reference
8
+ * arm's outcome is a factual transition from the reference's state to its own. A baseline/candidate group keeps
9
+ * its original shape (`baseline`, `candidate`, `transition`); any other group records `reference`, `arms` and
10
+ * `transitions` keyed by arm.
11
+ *
12
+ * @param {any[]} expectations
13
+ * @param {any[]} checks
14
+ * @param {{arms?: string[], reference?: string}} [options]
15
+ */
16
+ export function gradeComparisons(expectations, checks, { arms = DEFAULT_ARMS, reference = DEFAULT_REFERENCE } = {}) {
17
+ /** @type {Map<string, any[]>} */
18
+ const grouped = new Map();
19
+ const errors = /** @type {any[]} */ ([]);
20
+ for (const expectation of expectations) {
21
+ if (!hasOwn(expectation, "comparison")) continue;
22
+ if (typeof expectation.comparison !== "string" || !/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(expectation.comparison)) {
23
+ errors.push({ id: expectation.id, reason: "invalid comparison identity" });
24
+ continue;
25
+ }
26
+ const entries = grouped.get(expectation.comparison) ?? [];
27
+ entries.push(expectation);
28
+ grouped.set(expectation.comparison, entries);
29
+ }
30
+
31
+ const classic = isClassicPair(arms, reference);
32
+ const others = arms.filter((arm) => arm !== reference);
33
+ /** @type {Map<string, any>} */
34
+ const byCheck = new Map(checks.map((check) => [check.id, check]));
35
+ const comparisons = /** @type {any[]} */ ([]);
36
+ for (const [id, entries] of grouped) {
37
+ const expectationFor = Object.fromEntries(
38
+ arms.map((arm) => [arm, entries.filter((entry) => entry.variant === arm)]),
39
+ );
40
+ if (entries.length !== arms.length || arms.some((arm) => expectationFor[arm].length !== 1)) {
41
+ errors.push({
42
+ id,
43
+ reason: classic
44
+ ? "comparison requires one baseline and one candidate expectation"
45
+ : `comparison requires exactly one expectation for each arm: ${arms.join(", ")}`,
46
+ });
47
+ continue;
48
+ }
49
+ const checkFor = Object.fromEntries(arms.map((arm) => [arm, byCheck.get(expectationFor[arm][0].id)]));
50
+ if (!others.every((arm) => sameCheck(checkFor[reference], checkFor[arm]))) {
51
+ errors.push({ id, reason: "comparison expectations must describe the same deterministic check" });
52
+ continue;
53
+ }
54
+ if (classic) {
55
+ comparisons.push({
56
+ id,
57
+ kind: checkFor.baseline.kind,
58
+ baseline: { check: checkFor.baseline.id, state: checkFor.baseline.state },
59
+ candidate: { check: checkFor.candidate.id, state: checkFor.candidate.state },
60
+ transition: transition(checkFor.baseline.state, checkFor.candidate.state),
61
+ });
62
+ continue;
63
+ }
64
+ comparisons.push({
65
+ id,
66
+ kind: checkFor[reference].kind,
67
+ reference,
68
+ arms: Object.fromEntries(arms.map((arm) => [arm, { check: checkFor[arm].id, state: checkFor[arm].state }])),
69
+ transitions: Object.fromEntries(
70
+ others.map((arm) => [arm, transition(checkFor[reference].state, checkFor[arm].state)]),
71
+ ),
72
+ });
73
+ }
74
+ return { comparisons, errors };
75
+ }
76
+
77
+ function sameCheck(reference, other) {
78
+ return (
79
+ reference !== undefined &&
80
+ other !== undefined &&
81
+ reference.kind === other.kind &&
82
+ isDeepStrictEqual(reference.expected, other.expected)
83
+ );
84
+ }
85
+
86
+ function transition(reference, other) {
87
+ return [reference, other].every((state) => state === "pass" || state === "fail")
88
+ ? `${reference}-to-${other}`
89
+ : "unavailable";
90
+ }
@@ -5,15 +5,15 @@ import path from "node:path";
5
5
  import {
6
6
  completedCheck,
7
7
  hasOwn,
8
+ invalidExpectation,
8
9
  isContained,
9
10
  isSafeRelativePath,
11
+ placementProblem,
10
12
  readPaths,
11
13
  RESPONSE_EXPECTATIONS,
12
14
  textMatches,
13
15
  unavailableCheck,
14
- validBodyExpectation,
15
16
  validTurn,
16
- VARIANTS,
17
17
  } from "./grade-support.mjs";
18
18
 
19
19
  const ACTIVATION_EXPECTATIONS = new Set(["never", "on-turn", "by-turn", "not-before-turn"]);
@@ -21,17 +21,19 @@ const TOOL_CALL_EXPECTATIONS = new Set(["called", "succeeded", "failed", "not-ca
21
21
  const CONTEXT_TEXT_EXPECTATIONS = new Set(["contains", "not-contains", "equals"]);
22
22
  const CONTEXT_SURFACES = new Set(["system-prompt", "provider-context"]);
23
23
  const CONTEXT_REQUEST_SELECTORS = new Set(["first", "last"]);
24
+ const BODY = ["body"];
24
25
 
25
26
  export async function gradeSkillRead(group, runs, expectation) {
26
27
  const turn = expectation.turn ?? null;
27
28
  const timingExpectation = expectation.expect !== "never";
29
+ // The turn is checked here rather than as placement: a timing expectation needs one, and `never` takes none.
30
+ const placement = placementProblem(group, expectation, null, ["description"]);
28
31
  if (
29
- group.type !== "description" ||
30
- !VARIANTS.includes(expectation.variant) ||
32
+ placement !== null ||
31
33
  !ACTIVATION_EXPECTATIONS.has(expectation.expect) ||
32
34
  (timingExpectation ? turn === null || !validTurn(group, turn) : hasOwn(expectation, "turn"))
33
35
  ) {
34
- return { error: "invalid skill-read expectation" };
36
+ return invalidExpectation(expectation, placement);
35
37
  }
36
38
 
37
39
  const expected = { read: expectation.expect, turn };
@@ -49,17 +51,17 @@ export async function gradeSkillRead(group, runs, expectation) {
49
51
  export async function gradeResourceRead(group, runs, expectation) {
50
52
  const turn = expectation.turn ?? null;
51
53
  const indexed = expectation.resource === "skill" || expectation.resource === "context";
54
+ const placement = placementProblem(group, expectation, turn, ["description", "body"]);
52
55
  if (
53
- !VARIANTS.includes(expectation.variant) ||
56
+ placement !== null ||
54
57
  !["workspace", "skill", "context"].includes(expectation.resource) ||
55
58
  !["read", "not-read"].includes(expectation.expect) ||
56
59
  typeof expectation.path !== "string" ||
57
60
  !isSafeRelativePath(expectation.path) ||
58
- !validTurn(group, turn) ||
59
61
  (indexed && (!Number.isInteger(expectation.index) || expectation.index < 0)) ||
60
62
  (!indexed && hasOwn(expectation, "index"))
61
63
  ) {
62
- return { error: "invalid resource-read expectation" };
64
+ return invalidExpectation(expectation, placement);
63
65
  }
64
66
  const expected = {
65
67
  expect: expectation.expect,
@@ -109,15 +111,16 @@ export async function gradeContextText(group, runs, expectation) {
109
111
  const turn = expectation.turn ?? null;
110
112
  const surface = expectation.surface ?? "system-prompt";
111
113
  const request = expectation.request ?? "last";
114
+ const placement = placementProblem(group, expectation, turn, BODY);
112
115
  if (
113
- !validBodyExpectation(group, expectation, turn) ||
116
+ placement !== null ||
114
117
  !CONTEXT_SURFACES.has(surface) ||
115
118
  (!CONTEXT_REQUEST_SELECTORS.has(request) && !Number.isInteger(request)) ||
116
119
  (Number.isInteger(request) && request < 1) ||
117
120
  !CONTEXT_TEXT_EXPECTATIONS.has(expectation.expect) ||
118
121
  typeof expectation.value !== "string"
119
122
  ) {
120
- return { error: "invalid context-text expectation" };
123
+ return invalidExpectation(expectation, placement);
121
124
  }
122
125
 
123
126
  const expected = { expect: expectation.expect, value: expectation.value, surface, request, turn };
@@ -133,8 +136,9 @@ export async function gradeToolCall(group, runs, expectation) {
133
136
  const turn = expectation.turn ?? null;
134
137
  const contains = expectation.argumentContains ?? [];
135
138
  const notContains = expectation.argumentNotContains ?? [];
139
+ const placement = placementProblem(group, expectation, turn, BODY);
136
140
  if (
137
- !validBodyExpectation(group, expectation, turn) ||
141
+ placement !== null ||
138
142
  typeof expectation.tool !== "string" ||
139
143
  expectation.tool.trim() === "" ||
140
144
  !TOOL_CALL_EXPECTATIONS.has(expectation.expect) ||
@@ -143,7 +147,7 @@ export async function gradeToolCall(group, runs, expectation) {
143
147
  !Array.isArray(notContains) ||
144
148
  !notContains.every((value) => typeof value === "string")
145
149
  ) {
146
- return { error: "invalid tool-call expectation" };
150
+ return invalidExpectation(expectation, placement);
147
151
  }
148
152
 
149
153
  const expected = {
@@ -196,12 +200,9 @@ export async function gradeToolCall(group, runs, expectation) {
196
200
 
197
201
  export async function gradeResponseText(group, runs, expectation) {
198
202
  const turn = expectation.turn ?? null;
199
- if (
200
- !validBodyExpectation(group, expectation, turn) ||
201
- !RESPONSE_EXPECTATIONS.has(expectation.expect) ||
202
- typeof expectation.value !== "string"
203
- ) {
204
- return { error: "invalid response-text expectation" };
203
+ const placement = placementProblem(group, expectation, turn, BODY);
204
+ if (placement !== null || !RESPONSE_EXPECTATIONS.has(expectation.expect) || typeof expectation.value !== "string") {
205
+ return invalidExpectation(expectation, placement);
205
206
  }
206
207
 
207
208
  const expected = { expect: expectation.expect, value: expectation.value, turn };
@@ -2,15 +2,35 @@ import { createHash } from "node:crypto";
2
2
  import { lstat, readFile, realpath } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
 
5
- export const VARIANTS = ["baseline", "candidate"];
5
+ import { armNames } from "./arms.mjs";
6
+
6
7
  export const RESPONSE_EXPECTATIONS = new Set(["contains", "not-contains", "equals"]);
7
8
 
8
9
  export function hasOwn(value, key) {
9
10
  return Object.getOwnPropertyDescriptor(value, key) !== undefined;
10
11
  }
11
12
 
12
- export function validBodyExpectation(group, expectation, turn) {
13
- return group.type === "body" && VARIANTS.includes(expectation.variant) && validTurn(group, turn);
13
+ /** Whether an expectation's `variant` names one of the group's arms. */
14
+ export function isArm(group, name) {
15
+ return typeof name === "string" && armNames(group).includes(name);
16
+ }
17
+
18
+ /**
19
+ * Why an expectation cannot be graded in this group, decided by the group alone: its group type, its arm or its
20
+ * turn; null when it fits. Graders and definition loading share it, so a definition that loads is placed right.
21
+ */
22
+ export function placementProblem(group, expectation, turn, types) {
23
+ if (!types.includes(group.type)) return `it needs a ${types.join(" or ")} group`;
24
+ if (!isArm(group, expectation.variant)) {
25
+ return `its variant ${JSON.stringify(expectation.variant ?? null)} is not an arm of the group`;
26
+ }
27
+ if (!validTurn(group, turn)) return `its turn ${JSON.stringify(turn)} is not a declared turn`;
28
+ return null;
29
+ }
30
+
31
+ /** A grader's refusal of an expectation: its kind, and the placement problem when there is one. */
32
+ export function invalidExpectation(expectation, problem = null) {
33
+ return { error: `invalid ${expectation.kind} expectation${problem === null ? "" : `: ${problem}`}` };
14
34
  }
15
35
 
16
36
  export function validTurn(group, turn) {
@@ -60,10 +80,10 @@ export function readPaths(run, turn) {
60
80
  if (Array.isArray(run.turns)) {
61
81
  return run.turns.flatMap((entry) => (Array.isArray(entry.successfulReadPaths) ? entry.successfulReadPaths : []));
62
82
  }
63
- return Array.isArray(run.successfulReadPaths) ? run.successfulReadPaths : [];
83
+ return singleTurnReadPaths(run) ?? [];
64
84
  }
65
85
  if (!Array.isArray(run.turns)) {
66
- return turn === 1 && Array.isArray(run.successfulReadPaths) ? run.successfulReadPaths : null;
86
+ return turn === 1 ? singleTurnReadPaths(run) : null;
67
87
  }
68
88
  const observedTurn = run.turns.find((entry) => entry.turn === turn);
69
89
  return observedTurn && Array.isArray(observedTurn.successfulReadPaths) ? observedTurn.successfulReadPaths : null;
@@ -124,3 +144,10 @@ export function compareText(left, right) {
124
144
  if (left > right) return 1;
125
145
  return 0;
126
146
  }
147
+
148
+ // One-shot description runs record their reads under activation rather than at the top level.
149
+ function singleTurnReadPaths(run) {
150
+ if (Array.isArray(run.successfulReadPaths)) return run.successfulReadPaths;
151
+ if (Array.isArray(run.activation?.successfulReadPaths)) return run.activation.successfulReadPaths;
152
+ return null;
153
+ }
@@ -4,16 +4,18 @@ import {
4
4
  compareText,
5
5
  completedCheck,
6
6
  hasOwn,
7
+ invalidExpectation,
7
8
  isSafeRelativePath,
9
+ placementProblem,
8
10
  readWorkspaceFile,
9
11
  RESPONSE_EXPECTATIONS,
10
12
  textMatches,
11
13
  unavailableCheck,
12
- validBodyExpectation,
13
14
  validPathArray,
14
15
  workspaceEvidence,
15
16
  } from "./grade-support.mjs";
16
17
 
18
+ const BODY = ["body"];
17
19
  const JSON_EXPECTATIONS = new Set([
18
20
  "available",
19
21
  "missing",
@@ -26,13 +28,14 @@ const JSON_EXPECTATIONS = new Set([
26
28
 
27
29
  export async function gradePath(group, runs, expectation) {
28
30
  const turn = expectation.turn ?? null;
31
+ const placement = placementProblem(group, expectation, turn, BODY);
29
32
  if (
30
- !validBodyExpectation(group, expectation, turn) ||
33
+ placement !== null ||
31
34
  !["exists", "absent"].includes(expectation.expect) ||
32
35
  typeof expectation.path !== "string" ||
33
36
  !isSafeRelativePath(expectation.path)
34
37
  ) {
35
- return { error: "invalid path expectation" };
38
+ return invalidExpectation(expectation, placement);
36
39
  }
37
40
  const expected = { expect: expectation.expect, path: expectation.path, turn };
38
41
  const run = runs[expectation.variant];
@@ -56,12 +59,13 @@ export async function gradePath(group, runs, expectation) {
56
59
 
57
60
  export async function gradeChangedPaths(group, runs, expectation) {
58
61
  const turn = expectation.turn ?? null;
62
+ const placement = placementProblem(group, expectation, turn, BODY);
59
63
  if (
60
- !validBodyExpectation(group, expectation, turn) ||
64
+ placement !== null ||
61
65
  !["equals", "excludes"].includes(expectation.expect) ||
62
66
  !validPathArray(expectation.paths)
63
67
  ) {
64
- return { error: "invalid changed-paths expectation" };
68
+ return invalidExpectation(expectation, placement);
65
69
  }
66
70
  const expectedPaths = [...expectation.paths].sort(compareText);
67
71
  const expected = { expect: expectation.expect, paths: expectedPaths, turn };
@@ -81,16 +85,20 @@ export async function gradeChangedPaths(group, runs, expectation) {
81
85
 
82
86
  export async function gradeFileText(group, runs, expectation) {
83
87
  const turn = expectation.turn ?? null;
88
+ const line = expectation.line ?? null;
89
+ const placement = placementProblem(group, expectation, turn, BODY);
84
90
  if (
85
- !validBodyExpectation(group, expectation, turn) ||
91
+ placement !== null ||
86
92
  !RESPONSE_EXPECTATIONS.has(expectation.expect) ||
87
93
  typeof expectation.value !== "string" ||
88
94
  typeof expectation.path !== "string" ||
89
- !isSafeRelativePath(expectation.path)
95
+ !isSafeRelativePath(expectation.path) ||
96
+ (line !== null && !(Number.isInteger(line) && line >= 1))
90
97
  ) {
91
- return { error: "invalid file-text expectation" };
98
+ return invalidExpectation(expectation, placement);
92
99
  }
93
100
  const expected = { expect: expectation.expect, path: expectation.path, value: expectation.value, turn };
101
+ if (line !== null) expected.line = line;
94
102
  const run = runs[expectation.variant];
95
103
  if (!run || run.state !== "complete") return unavailableCheck(expectation, expected);
96
104
  const workspace = workspaceEvidence(run, turn);
@@ -102,13 +110,22 @@ export async function gradeFileText(group, runs, expectation) {
102
110
  sha256: file.sha256,
103
111
  turn,
104
112
  };
105
- const matches = file.state === "present" && textMatches(expectation.expect, expectation.value, file.text);
113
+ let text = file.state === "present" ? file.text : null;
114
+ if (line !== null) {
115
+ // One line, without its line ending. A line that does not exist fails every expectation,
116
+ // so an empty or short file cannot pass a not-contains check by having nothing to read.
117
+ const lines = text === null || text === "" ? [] : text.split(/\r?\n/);
118
+ text = line <= lines.length ? lines[line - 1] : null;
119
+ observed.line = text === null ? "missing" : "present";
120
+ }
121
+ const matches = text !== null && textMatches(expectation.expect, expectation.value, text);
106
122
  return completedCheck(expectation, expected, observed, matches);
107
123
  }
108
124
 
109
125
  export async function gradeJson(group, runs, expectation) {
110
126
  const turn = expectation.turn ?? null;
111
- if (!validJsonExpectation(group, expectation, turn)) return { error: "invalid json expectation" };
127
+ const placement = placementProblem(group, expectation, turn, BODY);
128
+ if (placement !== null || !validJsonExpectation(expectation)) return invalidExpectation(expectation, placement);
112
129
 
113
130
  const expected = {
114
131
  expect: expectation.expect,
@@ -126,10 +143,9 @@ export async function gradeJson(group, runs, expectation) {
126
143
  return completedCheck(expectation, expected, observed, jsonMatches(expectation, observed));
127
144
  }
128
145
 
129
- function validJsonExpectation(group, expectation, turn) {
146
+ function validJsonExpectation(expectation) {
130
147
  const fieldExpectation = ["field-present", "field-absent", "field-equals"].includes(expectation.expect);
131
148
  return (
132
- validBodyExpectation(group, expectation, turn) &&
133
149
  typeof expectation.path === "string" &&
134
150
  isSafeRelativePath(expectation.path) &&
135
151
  JSON_EXPECTATIONS.has(expectation.expect) &&
@@ -0,0 +1,101 @@
1
+ import { armNames, referenceArm } from "./arms.mjs";
2
+ import { gradeCommand } from "./grade-command.mjs";
3
+ import { gradeComparisons } from "./grade-comparison.mjs";
4
+ import {
5
+ gradeContextText,
6
+ gradeResourceRead,
7
+ gradeResponseText,
8
+ gradeSkillRead,
9
+ gradeToolCall,
10
+ } from "./grade-interaction.mjs";
11
+ import { gradeChangedPaths, gradeFileText, gradeJson, gradePath } from "./grade-workspace.mjs";
12
+
13
+ const GRADERS = new Map([
14
+ ["skill-read", gradeSkillRead],
15
+ ["resource-read", gradeResourceRead],
16
+ ["path", gradePath],
17
+ ["changed-paths", gradeChangedPaths],
18
+ ["file-text", gradeFileText],
19
+ ["json", gradeJson],
20
+ ["response-text", gradeResponseText],
21
+ ["context-text", gradeContextText],
22
+ ["tool-call", gradeToolCall],
23
+ ["command", gradeCommand],
24
+ ]);
25
+
26
+ /**
27
+ * @param {any} group
28
+ * @param {any} runs
29
+ * @param {any} evidence
30
+ * @returns {Promise<any>}
31
+ */
32
+ export async function gradeDeterministic(group, runs, evidence) {
33
+ const { checks, errors } = await gradeEach(group, runs, group.expectations);
34
+ const compared = gradeComparisons(group.expectations, checks, {
35
+ arms: armNames(group),
36
+ reference: referenceArm(group),
37
+ });
38
+ errors.push(...compared.errors);
39
+ return {
40
+ schema_version: 1,
41
+ state: reportState(checks, errors),
42
+ evidence,
43
+ checks,
44
+ comparisons: compared.comparisons,
45
+ errors,
46
+ };
47
+ }
48
+
49
+ /**
50
+ * What grading would refuse in a loaded group's expectations that the definition alone decides: a kind in a group
51
+ * type it cannot grade, an arm or turn the group lacks, field values its grader rejects, or comparison members
52
+ * that do not describe one check in every arm. Each grader runs with no run evidence, so the check is the
53
+ * grader's own and runs before anything is spent. An unknown kind, and any comparison it belongs to, is left to
54
+ * grading, where it is a grade error.
55
+ *
56
+ * @returns {Promise<Array<{ expectation?: string, comparison?: string, reason: string }>>}
57
+ */
58
+ export async function expectationProblems(group) {
59
+ const known = group.expectations.filter((expectation) => GRADERS.has(expectation.kind));
60
+ const { checks, errors } = await gradeEach(group, {}, known);
61
+ const unknownComparisons = new Set(
62
+ group.expectations
63
+ .filter((expectation) => !GRADERS.has(expectation.kind) && Object.hasOwn(expectation, "comparison"))
64
+ .map((expectation) => expectation.comparison),
65
+ );
66
+ const compared = gradeComparisons(
67
+ group.expectations.filter((expectation) => !unknownComparisons.has(expectation.comparison)),
68
+ checks,
69
+ { arms: armNames(group), reference: referenceArm(group) },
70
+ );
71
+ return [
72
+ ...errors.map(({ id, reason }) => ({ expectation: id, reason })),
73
+ ...compared.errors.map(({ id, reason }) => ({ comparison: id, reason })),
74
+ ];
75
+ }
76
+
77
+ async function gradeEach(group, runs, expectations) {
78
+ const checks = /** @type {Array<any>} */ ([]);
79
+ const errors = /** @type {Array<any>} */ ([]);
80
+ for (const expectation of expectations) {
81
+ const grader = GRADERS.get(expectation.kind);
82
+ if (!grader) {
83
+ errors.push({ id: expectation.id, reason: `unsupported expectation kind: ${expectation.kind}` });
84
+ continue;
85
+ }
86
+ try {
87
+ const result = await grader(group, runs, expectation);
88
+ if (result.error) errors.push({ id: expectation.id, reason: result.error });
89
+ else checks.push(result);
90
+ } catch (error) {
91
+ errors.push({ id: expectation.id, reason: error instanceof Error ? error.message : String(error) });
92
+ }
93
+ }
94
+ return { checks, errors };
95
+ }
96
+
97
+ function reportState(checks, errors) {
98
+ if (errors.length > 0) return "grade-error";
99
+ if (checks.length > 0 && checks.every((check) => check.state === "unavailable")) return "unavailable";
100
+ return "complete";
101
+ }
@@ -0,0 +1,98 @@
1
+ // Extension points for later evaluator features. Every registry starts empty, and with nothing registered the
2
+ // evaluator writes exactly what it wrote before. A hook that throws is recorded as `{ error }` in its own slot;
3
+ // it never fails the run, the grade or the aggregate.
4
+
5
+ const HOOK_NAME = /^[a-z][A-Za-z0-9]*$/;
6
+ // Fields an aggregate group entry already has; a section may not replace one.
7
+ const AGGREGATE_GROUP_FIELDS = new Set([
8
+ "id",
9
+ "trials",
10
+ "unreadableGrades",
11
+ "gradeErrors",
12
+ "runStates",
13
+ "comparisons",
14
+ "checks",
15
+ ]);
16
+
17
+ function createRegistry(kind, reserved = new Set()) {
18
+ const hooks = new Map();
19
+ return {
20
+ register(name, hook) {
21
+ if (typeof name !== "string" || !HOOK_NAME.test(name) || reserved.has(name)) {
22
+ throw new Error(`${kind} name must be a camelCase identifier that is not reserved: ${name}`);
23
+ }
24
+ if (typeof hook !== "function") throw new Error(`${kind} ${name} must be a function`);
25
+ if (hooks.has(name)) throw new Error(`${kind} ${name} is already registered`);
26
+ hooks.set(name, hook);
27
+ return () => {
28
+ if (hooks.get(name) === hook) hooks.delete(name);
29
+ };
30
+ },
31
+ entries() {
32
+ return [...hooks.entries()];
33
+ },
34
+ };
35
+ }
36
+
37
+ function failure(error) {
38
+ return { error: error instanceof Error ? error.message : String(error) };
39
+ }
40
+
41
+ const aggregators = createRegistry("aggregator", AGGREGATE_GROUP_FIELDS);
42
+ const postRunHooks = createRegistry("post-run hook");
43
+ const runMetricsHooks = createRegistry("run-metrics hook");
44
+
45
+ /** Aggregator: `hook({ id, arms, reference, trials: [{ id, directory, state, grade, runs }] })`, where `directory` is the trial's group directory; its result is stored on the aggregate group entry under `<name>`. */
46
+ export const registerAggregator = aggregators.register;
47
+
48
+ /** Post-run hook: `hook({ group, arm, run, root, directory, signal })` for each executed run, before run.json is written; its result is stored in run.json under `postRun.<name>`. */
49
+ export const registerPostRunHook = postRunHooks.register;
50
+
51
+ /** Run-metrics hook: synchronous `hook({ group, arm, subject, observation, run })` where pi.mjs assembles run.json; its returned object is merged into `run.metrics`. */
52
+ export const registerRunMetricsHook = runMetricsHooks.register;
53
+
54
+ export function hasAggregators() {
55
+ return aggregators.entries().length > 0;
56
+ }
57
+
58
+ /** Each registered aggregator's section for one aggregate group, by name. */
59
+ export async function aggregateSections(input) {
60
+ const sections = {};
61
+ for (const [name, hook] of aggregators.entries()) {
62
+ try {
63
+ sections[name] = await hook(input);
64
+ } catch (error) {
65
+ sections[name] = failure(error);
66
+ }
67
+ }
68
+ return sections;
69
+ }
70
+
71
+ /** Each registered post-run hook's record for one run, by name; a hook that returns undefined records nothing, and null means nothing was recorded. */
72
+ export async function postRunRecords(context) {
73
+ const records = {};
74
+ for (const [name, hook] of postRunHooks.entries()) {
75
+ try {
76
+ const record = await hook(context);
77
+ if (record !== undefined) records[name] = record;
78
+ } catch (error) {
79
+ records[name] = failure(error);
80
+ }
81
+ }
82
+ return Object.keys(records).length === 0 ? null : records;
83
+ }
84
+
85
+ /** The registered run-metrics hooks' fields merged in registration order; null when none is registered. */
86
+ export function runMetrics(context) {
87
+ const entries = runMetricsHooks.entries();
88
+ if (entries.length === 0) return null;
89
+ const metrics = {};
90
+ for (const [name, hook] of entries) {
91
+ try {
92
+ Object.assign(metrics, hook(context));
93
+ } catch (error) {
94
+ metrics[name] = failure(error);
95
+ }
96
+ }
97
+ return metrics;
98
+ }