@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,732 @@
1
+ import { mkdir, realpath } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { armNames } from "./arms.mjs";
5
+ import { budgetEvidence, charge, costEvidence, measuredCost, reserve, runBudgetEvidence } from "./budget.mjs";
6
+ import { COMMAND_TOOL, loadDefinition, selectDefinition } from "./definitions.mjs";
7
+ import { createInvocationId, fileIdentity, writeJson, writeText } from "./evidence.mjs";
8
+ import { gradeDeterministic } from "./grade.mjs";
9
+ import { prepareFreeflow } from "./freeflow.mjs";
10
+ import { postRunRecords } from "./hooks.mjs";
11
+ import { hostAdapter } from "./hosts/index.mjs";
12
+ import { identityRefusal, inputIdentity } from "./identity.mjs";
13
+ import { prepareSourceExtensions } from "./build-source.mjs";
14
+ import { armParticipants, runParticipants } from "./participants.mjs";
15
+ import { prepareShell } from "./shell.mjs";
16
+ import { enforceReferenceChecks } from "./reference.mjs";
17
+ import { createLimiter, withCpuSlot } from "./queue.mjs";
18
+ import { adoptRun, appendIndex, createReuse } from "./reuse.mjs";
19
+ import { prepareFixture, prepareRuntime, verifyDescriptionOnlyRevision } from "./sandbox.mjs";
20
+ import { applySourceOverrides } from "./source-override.mjs";
21
+ import { runBody, runDescription, VariantSetupError } from "./subject.mjs";
22
+ import { unclearedFlags } from "./scan.mjs";
23
+ import { armSealing } from "./seal.mjs";
24
+ import { applyValidityGate } from "./validity.mjs";
25
+
26
+ const DESCRIPTION_TOOLS = new Set(["read"]);
27
+ const BODY_TOOLS = new Set(["read", "write", "edit", "ls", "find", "grep"]);
28
+ // Native tools must be separated from extension tools before CLI tool selection is built.
29
+ const NATIVE_TOOLS = new Set(["read", "bash", "powershell", "edit", "write", "grep", "find", "ls"]);
30
+ const BACKGROUND_TOOLS = new Set(["bash_background", "monitor"]);
31
+ const DEFAULT_RUNTIME = {
32
+ session: false,
33
+ prompt: "isolated",
34
+ extensions: [],
35
+ environment: { literal: {}, inherit: [] },
36
+ };
37
+
38
+ /** A group's host: its configuration's `host.name`, which every arm shares. Pi for groups resolved before it was recorded. */
39
+ export function groupHost(group) {
40
+ return group.host ?? group.runtime?.host ?? "pi";
41
+ }
42
+
43
+ /** Where results are stored: `--results` when given, else `<root>/.skill-eval/runs`. */
44
+ export function resultsDirectory(root, results = null) {
45
+ return results === null || results === undefined
46
+ ? path.join(root, ".skill-eval", "runs")
47
+ : path.resolve(root, results);
48
+ }
49
+
50
+ /** The reuse state for one run or aggregate (see reuse.mjs); `enabled` is `--reuse`. */
51
+ export function createRunReuse(runsDirectory, enabled) {
52
+ return createReuse({
53
+ resultsDirectory: runsDirectory,
54
+ enabled,
55
+ hostVersion: (host) => hostAdapter(host).version(),
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Runs the selection once. Subjects run through `subjects` (a limiter shared by every invocation of one
61
+ * aggregate; `jobs` at once); with one job, groups and arms run in order exactly as before. Cancellation
62
+ * reaches running subjects; budget exhaustion only stops new ones from starting.
63
+ *
64
+ * @param {string} definitionFile
65
+ * @param {any} selectors
66
+ * @param {{root?: string, signal?: AbortSignal, budget?: any, dryRun?: boolean, jobs?: number, subjects?: ReturnType<typeof createLimiter>, results?: string | null, reuse?: any, groupRange?: [number, number] | null, loginsRefreshed?: boolean}} options
67
+ */
68
+ export async function runEvaluation(definitionFile, selectors = {}, options = {}) {
69
+ const { root = process.cwd(), signal, budget = null, dryRun = false, groupRange = null } = options;
70
+ const { skipReferenceCheck = false } = options;
71
+ const subjects = options.subjects ?? createLimiter(options.jobs ?? 1);
72
+ const runsDirectory = resultsDirectory(root, options.results);
73
+ const reuse = options.reuse ?? createRunReuse(runsDirectory, false);
74
+ const definitionPath = await realpath(path.resolve(root, definitionFile));
75
+ const definition = await loadDefinition(definitionPath, { root });
76
+ const selection = selectDefinition(definition, selectors);
77
+ // A pilot runs the first groups of the selection, and the batch after it the rest.
78
+ if (groupRange !== null) selection.groups = selection.groups.slice(groupRange[0], groupRange[1]);
79
+ // --source: an arm's Git source refs replaced for this run only, before anything reads them.
80
+ const sources = options.sources && Object.keys(options.sources).length > 0 ? options.sources : null;
81
+ applySourceOverrides(selection, sources);
82
+ assertSupportedSelection(selection);
83
+
84
+ // Canonical evidence needs every working-tree input recoverable from one commit; anything else is a dry run.
85
+ const identity = await inputIdentity(root, workingTreeInputs(selection, definitionPath, root));
86
+ const refusal = identityRefusal(identity);
87
+ if (refusal !== null && !dryRun) throw new Error(refusal);
88
+ const hostVersion = await checkHostVersion(selection);
89
+ const hostExtensions = await resolveSelectedExtensions(selection);
90
+ if (!options.loginsRefreshed) await refreshSelectedLogins(selection);
91
+ const invocationId = createInvocationId();
92
+ const resultDirectory = path.join(runsDirectory, invocationId);
93
+ await mkdir(runsDirectory, { recursive: true });
94
+ await mkdir(resultDirectory);
95
+ await writeJson(path.join(resultDirectory, "invocation.json"), {
96
+ schema_version: 1,
97
+ id: invocationId,
98
+ definition: definitionPath,
99
+ results: runsDirectory,
100
+ jobs: subjects.limit,
101
+ reuse: reuse.enabled,
102
+ ...(sources === null ? {} : { sources }),
103
+ selection: {
104
+ group: selectors.group ?? null,
105
+ variant: selectors.variant ?? null,
106
+ groups: selection.groups.map((entry) => ({
107
+ id: entry.group.id,
108
+ position: entry.position,
109
+ variants: entry.variants,
110
+ })),
111
+ },
112
+ startedAt: new Date().toISOString(),
113
+ });
114
+
115
+ // A declared reference must solve its task before any subject starts (SPEC-002 A9).
116
+ await enforceReferenceChecks(selection, { root, resultDirectory, skip: skipReferenceCheck, signal });
117
+
118
+ // Budget exhaustion stops only subjects not yet started; a subject already running completes and is charged.
119
+ const context = {
120
+ root,
121
+ invocationId,
122
+ resultDirectory,
123
+ signal,
124
+ stopped: () => Boolean(signal?.aborted || budget?.exhausted),
125
+ budget,
126
+ subjects,
127
+ // A clean working tree is identified by its commit, recorded on each working-tree source.
128
+ sourceCommit: refusal === null ? identity.commit : null,
129
+ reuse,
130
+ dryRun,
131
+ indexEntries: [],
132
+ sources,
133
+ // This invocation's own spend, apart from the run's shared budget, which every trial charges.
134
+ cost: { spent: 0, subjects: 0, unmeasured: 0 },
135
+ };
136
+ const runOne = (selected) =>
137
+ runGroup({ ...context, selected, hostExtensions: hostExtensions.get(selected.group.id) });
138
+ const groups =
139
+ subjects.limit === 1 ? await sequential(selection.groups, runOne) : await Promise.all(selection.groups.map(runOne));
140
+ // Canonical complete runs become reusable, with or without --reuse; an index that cannot be written never fails
141
+ // the run.
142
+ if (!dryRun) await appendIndex(runsDirectory, context.indexEntries).catch(() => {});
143
+ const state = batchState(groups);
144
+ const summary = {
145
+ schema_version: 1,
146
+ id: invocationId,
147
+ state,
148
+ definitionKind: selection.definitionKind,
149
+ dryRun,
150
+ inputs: identity.repository
151
+ ? { commit: identity.commit, uncommitted: identity.uncommitted }
152
+ : { commit: null, uncommitted: [], repository: false },
153
+ groups,
154
+ completedAt: new Date().toISOString(),
155
+ };
156
+ if (hostVersion !== null) summary.hostVersion = hostVersion;
157
+ summary.cost = costEvidence(context.cost);
158
+ // The budget is the whole run's, shared by every trial: its total is what the run had spent when this one ended.
159
+ if (budget !== null) summary.budget = runBudgetEvidence(budget);
160
+ await writeJson(path.join(resultDirectory, "summary.json"), summary);
161
+ return { id: invocationId, path: resultDirectory, state, summary };
162
+ }
163
+
164
+ /** Every path a run reads from the working tree: definition files, fixtures, runtime bundles, working-tree subjects. */
165
+ function workingTreeInputs(selection, definitionPath, root) {
166
+ const inputs = new Set([definitionPath]);
167
+ for (const { group, variants } of selection.groups) {
168
+ for (const file of group.files ?? []) inputs.add(file);
169
+ if (group.fixture !== null) inputs.add(path.resolve(root, group.fixture));
170
+ for (const bundle of group.runtime?.extensions ?? []) {
171
+ for (const resource of bundle.resources) inputs.add(path.resolve(root, resource));
172
+ }
173
+ for (const [arm, state] of Object.entries(variants)) {
174
+ const variant = group.variants[arm];
175
+ if (state !== "selected" || variant.source.kind !== "working-tree") continue;
176
+ for (const entry of [...variant.skills, ...variant.context]) inputs.add(path.resolve(root, entry));
177
+ }
178
+ }
179
+ return [...inputs];
180
+ }
181
+
182
+ /** Each selected arm's declared host extensions, found among the host's installed packages before anything starts. */
183
+ async function resolveSelectedExtensions(selection) {
184
+ const resolved = new Map();
185
+ for (const { group, variants } of selection.groups) {
186
+ const arms = Object.fromEntries(armNames(group).map((arm) => [arm, []]));
187
+ for (const [arm, state] of Object.entries(variants)) {
188
+ if (state === "selected") {
189
+ arms[arm] = await hostAdapter(groupHost(group)).resolveExtensions(group.variants[arm].hostExtensions ?? [], {
190
+ deferSources: true,
191
+ });
192
+ }
193
+ }
194
+ resolved.set(group.id, arms);
195
+ }
196
+ return resolved;
197
+ }
198
+
199
+ async function sequential(items, work) {
200
+ const results = [];
201
+ for (const item of items) results.push(await work(item));
202
+ return results;
203
+ }
204
+
205
+ /**
206
+ * Before a batch, makes every OAuth login the selected arms use valid for the target window, refreshing it
207
+ * once, centrally, so no subject has to refresh its own copy. Trials call it once for all their invocations.
208
+ */
209
+ export async function refreshSelectedLogins(selection) {
210
+ const providers = new Map();
211
+ for (const { group, variants } of selection.groups) {
212
+ const host = groupHost(group);
213
+ if (!providers.has(host)) providers.set(host, new Set());
214
+ for (const [arm, state] of Object.entries(variants)) {
215
+ const model = group.variants[arm].model?.model;
216
+ if (state === "selected" && typeof model === "string" && model.includes("/")) {
217
+ providers.get(host).add(model.split("/")[0]);
218
+ }
219
+ }
220
+ }
221
+ for (const [host, names] of providers) await hostAdapter(host).refreshLogins([...names]);
222
+ }
223
+
224
+ /**
225
+ * A declared host version must match the installed host before anything starts. Returns the installed version of
226
+ * the one host whose version was declared, or null when none was.
227
+ */
228
+ async function checkHostVersion(selection) {
229
+ const declared = new Map();
230
+ for (const { group, variants } of selection.groups) {
231
+ const host = groupHost(group);
232
+ for (const [arm, state] of Object.entries(variants)) {
233
+ const version = group.configurations?.[arm]?.host?.version;
234
+ if (state !== "selected" || version === undefined) continue;
235
+ if (!declared.has(host)) declared.set(host, new Set());
236
+ declared.get(host).add(version);
237
+ }
238
+ }
239
+ if (declared.size === 0) return null;
240
+ const installed = {};
241
+ for (const [host, versions] of declared) {
242
+ installed[host] = await hostAdapter(host).version();
243
+ for (const version of versions) {
244
+ if (version !== installed[host]) {
245
+ throw new Error(`the definition declares ${host} ${version}, but the installed ${host} is ${installed[host]}`);
246
+ }
247
+ }
248
+ }
249
+ // One host's version is a string, as it always was; a selection declaring versions for several hosts records each.
250
+ const hosts = Object.keys(installed);
251
+ return hosts.length === 1 ? installed[hosts[0]] : installed;
252
+ }
253
+
254
+ function assertSupportedSelection(selection) {
255
+ for (const selected of selection.groups) {
256
+ const { group } = selected;
257
+ if (group.type !== "description" && group.type !== "body") {
258
+ throw new Error("skill-eval run currently supports description and body groups only");
259
+ }
260
+ const supportedTools = new Set(group.type === "body" ? BODY_TOOLS : DESCRIPTION_TOOLS);
261
+ // bash only through a declared, verified shell isolation (definitions.mjs and shell.mjs).
262
+ if (group.type === "body" && Object.values(group.variants).every((variant) => variant.shell)) {
263
+ supportedTools.add("bash");
264
+ }
265
+ const unsupportedNativeTools = group.tools.filter((tool) => NATIVE_TOOLS.has(tool) && !supportedTools.has(tool));
266
+ if (unsupportedNativeTools.length > 0) {
267
+ const hint = unsupportedNativeTools.includes("bash")
268
+ ? "; bash runs only in a body group whose every arm declares a shell isolation (configuration.shell)"
269
+ : "";
270
+ throw new Error(
271
+ `${group.type} execution does not support native tools: ${unsupportedNativeTools.join(", ")}${hint}`,
272
+ );
273
+ }
274
+ // The evaluator supplies run_command itself when the definition declares commands.
275
+ const customTools = group.tools.filter(
276
+ (tool) => !NATIVE_TOOLS.has(tool) && !supportedTools.has(tool) && tool !== COMMAND_TOOL,
277
+ );
278
+ if (group.type === "description" && customTools.length > 0) {
279
+ throw new Error(`${group.type} execution does not support custom tools: ${customTools.join(", ")}`);
280
+ }
281
+ // Freeflow's background commands outlive the call that starts them, so they run only in a container, which the
282
+ // evaluator removes when the subject ends (guard-rules.mjs routes them there).
283
+ const background = group.tools.filter((tool) => BACKGROUND_TOOLS.has(tool));
284
+ if (background.length > 0 && !Object.values(group.variants).every((variant) => variant.shell?.container)) {
285
+ throw new Error(
286
+ `${background.join(" and ")} run only in a container environment: every arm needs configuration.environment`,
287
+ );
288
+ }
289
+ // Freeflow registers its own tools, so a Freeflow configuration also allows custom tool names.
290
+ const freeflowLoaded = Object.values(group.variants).some((variant) => variant.freeflow);
291
+ if (customTools.length > 0 && (group.runtime?.extensions?.length ?? 0) === 0 && !freeflowLoaded) {
292
+ throw new Error(
293
+ `${group.type} execution requires declared extensions for custom tools: ${customTools.join(", ")}`,
294
+ );
295
+ }
296
+ }
297
+ }
298
+
299
+ export { budgetEvidence };
300
+
301
+ /**
302
+ * One subject in a slot: it waits for a free slot, starts only if nothing stopped the run and the budget can
303
+ * reserve for it, and is charged what it cost, to the run's budget and to this invocation's own `cost`. Returns
304
+ * `{ run, executed }`.
305
+ */
306
+ async function runSubject({ group, variant, stopped, budget, cost, subjects, execute }) {
307
+ return subjects.run(async () => {
308
+ if (stopped()) return { run: cancelledRun(group, variant), executed: false };
309
+ const reservation = reserve(budget);
310
+ if (reservation === null) return { run: cancelledRun(group, variant), executed: false };
311
+ const run = await execute();
312
+ const spent = measuredCost(run.usage);
313
+ charge(budget, reservation, spent ?? 0);
314
+ cost.subjects += 1;
315
+ if (spent === null) cost.unmeasured += 1;
316
+ else cost.spent += spent;
317
+ return { run, executed: true };
318
+ });
319
+ }
320
+
321
+ async function runGroup({
322
+ selected,
323
+ root,
324
+ invocationId,
325
+ resultDirectory,
326
+ signal,
327
+ stopped,
328
+ budget,
329
+ subjects,
330
+ sourceCommit = null,
331
+ hostExtensions = {},
332
+ reuse,
333
+ dryRun,
334
+ indexEntries,
335
+ sources = null,
336
+ cost,
337
+ }) {
338
+ const { group } = selected;
339
+ const arms = armNames(group);
340
+ const groupDirectory = path.join(resultDirectory, "groups", group.id);
341
+ await mkdir(groupDirectory, { recursive: true });
342
+ await writeJson(path.join(groupDirectory, "definition.json"), group);
343
+
344
+ let fixture = null;
345
+ let runtime = null;
346
+ let freeflow = Object.fromEntries(arms.map((arm) => [arm, null]));
347
+ let resourceError = null;
348
+ let resourceDetails = null;
349
+ let confinement = {};
350
+ if (!stopped()) {
351
+ try {
352
+ fixture = await prepareFixture({ declaredPath: group.fixture, root, groupDirectory });
353
+ runtime = await prepareRuntime({
354
+ runtime: group.runtime ?? { host: groupHost(group), ...DEFAULT_RUNTIME },
355
+ root,
356
+ groupDirectory,
357
+ });
358
+ freeflow = await withCpuSlot(() => prepareFreeflow({ variants: group.variants, root, groupDirectory }));
359
+ // Building from source and probing the shell are local CPU work, so they wait for a --cpu-jobs slot.
360
+ const extensions = hostExtensions;
361
+ hostExtensions = await withCpuSlot(() => prepareSourceExtensions({ extensions, root, groupDirectory, signal }));
362
+ const built = hostExtensions;
363
+ confinement = await withCpuSlot(() =>
364
+ prepareShell({ group, variants: selected.variants, hostExtensions: built, groupDirectory, signal }),
365
+ );
366
+ if (group.revision === "description-only") {
367
+ await verifyDescriptionOnlyRevision({
368
+ variants: group.variants,
369
+ root,
370
+ destinationRoot: path.join(groupDirectory, "resources", "description-only-check"),
371
+ });
372
+ }
373
+ } catch (error) {
374
+ resourceError = error instanceof Error ? error.message : String(error);
375
+ resourceDetails = error?.details ?? null;
376
+ if (resourceDetails?.confinement) confinement = resourceDetails.confinement;
377
+ }
378
+ }
379
+
380
+ const runs = {};
381
+ const runFiles = {};
382
+ const keys = {};
383
+ const reusedFrom = {};
384
+ const runArm = async (variant) => {
385
+ const variantDirectory = path.join(groupDirectory, variant);
386
+ await mkdir(variantDirectory, { recursive: true });
387
+ if (selected.variants[variant] === "not-selected") {
388
+ runs[variant] = notSelectedRun(group, variant);
389
+ } else if (stopped()) {
390
+ runs[variant] = cancelledRun(group, variant);
391
+ } else if (resourceError === null) {
392
+ // A canonical run has a reuse key, and a new complete run is indexed under it with or without --reuse, so a
393
+ // run made without it (a first run, a pilot on its own) can stand in later. Only --reuse claims an indexed run.
394
+ keys[variant] = dryRun ? null : await reuse.keyFor(group, variant, root).catch(() => null);
395
+ const claimed = await reuse.claim(keys[variant]);
396
+ const adopted = claimed === null ? null : await adoptRun(claimed, variantDirectory).catch(() => null);
397
+ if (adopted !== null) {
398
+ runs[variant] = adopted;
399
+ reusedFrom[variant] = adopted.reused;
400
+ } else {
401
+ const { run, executed } = await runSubject({
402
+ group,
403
+ variant,
404
+ stopped,
405
+ budget,
406
+ cost,
407
+ subjects,
408
+ execute: () =>
409
+ executeVariant({
410
+ group,
411
+ variant,
412
+ root,
413
+ variantDirectory,
414
+ fixture,
415
+ runtime,
416
+ freeflow: freeflow[variant],
417
+ hostExtensions: hostExtensions[variant] ?? [],
418
+ signal,
419
+ }),
420
+ });
421
+ runs[variant] = run;
422
+ if (executed) {
423
+ if (confinement[variant] !== undefined) run.confinement = confinement[variant];
424
+ // What the subject's own code could reach: the network policy and where each path ran.
425
+ run.sealing = armSealing(group, variant, confinement[variant]);
426
+ if (sources?.[variant] !== undefined) run.sourceOverride = sources[variant];
427
+ if (sourceCommit !== null && run.resources?.source?.kind === "working-tree") {
428
+ run.resources.source.commit = sourceCommit;
429
+ }
430
+ // A run that shows no model at work is invalid before anything grades it; its graders then do not start.
431
+ applyValidityGate(run);
432
+ // Post-run hooks see the finished run before it is persisted; their records land in run.json.
433
+ const records = await postRunRecords({ group, arm: variant, run, root, directory: variantDirectory, signal });
434
+ if (records !== null) run.postRun = records;
435
+ }
436
+ }
437
+ } else {
438
+ runs[variant] = invalidRun(group, variant, resourceError);
439
+ if (resourceDetails !== null) runs[variant].error.details = resourceDetails;
440
+ if (confinement[variant] !== undefined) runs[variant].confinement = confinement[variant];
441
+ }
442
+ const persisted = await persistRunOrFailure(variantDirectory, runs[variant]);
443
+ runs[variant] = persisted.run;
444
+ runFiles[variant] = persisted.file;
445
+ };
446
+ if (subjects.limit === 1) await sequential(arms, runArm);
447
+ else await Promise.all(arms.map(runArm));
448
+
449
+ const evidence = {};
450
+ for (const arm of arms) evidence[arm] = await runFileIdentity(runFiles[arm]);
451
+ const grade = await createGrade(group, runs, evidence);
452
+ const persistedGrade = await persistGrade(groupDirectory, grade);
453
+ const selectedRuns = arms
454
+ .filter((variant) => selected.variants[variant] === "selected")
455
+ .map((variant) => runs[variant]);
456
+ const selectedState = selectedGroupState(selectedRuns, persistedGrade.grade);
457
+ let groupState = selectedState;
458
+ if (selectedState !== "cancelled" && resourceError !== null) groupState = "invalid";
459
+ const groupResult = {
460
+ id: group.id,
461
+ position: selected.position,
462
+ state: groupState,
463
+ variants: Object.fromEntries(arms.map((variant) => [variant, runs[variant].state])),
464
+ grade: persistedGrade.grade.state,
465
+ artifacts: { grade: persistedGrade.artifact, group: "group.json" },
466
+ errors: persistedGrade.errors,
467
+ };
468
+ if (Object.keys(reusedFrom).length > 0) groupResult.reused = reusedFrom;
469
+ // Why each invalid arm is invalid, so a pilot or a view can say it without opening the run.
470
+ const invalid = Object.fromEntries(
471
+ arms.filter((arm) => runs[arm].state === "invalid").map((arm) => [arm, runs[arm].error?.message ?? "invalid"]),
472
+ );
473
+ if (Object.keys(invalid).length > 0) groupResult.invalid = invalid;
474
+ // Each arm's transcript-scan flags no person has cleared yet; such a run is held out of every claim.
475
+ const flagged = {};
476
+ for (const arm of arms) {
477
+ const uncleared = await unclearedFlags(runs[arm], path.join(groupDirectory, arm));
478
+ if (uncleared.length > 0) flagged[arm] = uncleared;
479
+ }
480
+ if (Object.keys(flagged).length > 0) groupResult.flagged = flagged;
481
+ // A complete run with a readable grade is indexed for reuse; a reused run is not, so it is reused once.
482
+ const gradeReadable =
483
+ persistedGrade.artifact === "deterministic-grade.json" && persistedGrade.grade.state !== "grade-error";
484
+ for (const arm of arms) {
485
+ if (!gradeReadable || typeof keys[arm] !== "string" || runs[arm].state !== "complete" || runs[arm].reused) continue;
486
+ indexEntries.push({
487
+ key: keys[arm],
488
+ result: invocationId,
489
+ group: group.id,
490
+ arm,
491
+ indexedAt: new Date().toISOString(),
492
+ });
493
+ }
494
+ return persistGroupResult(groupDirectory, groupResult);
495
+ }
496
+
497
+ function batchState(groups) {
498
+ if (groups.some((group) => group.state === "cancelled")) return "cancelled";
499
+ if (groups.every((group) => group.state === "complete")) return "complete";
500
+ return "partially-complete";
501
+ }
502
+
503
+ function selectedGroupState(runs, grade) {
504
+ if (runs.some((run) => run.state === "cancelled")) return "cancelled";
505
+ // A grade whose every selected check is unavailable observed nothing, so the group is not complete.
506
+ if (runs.every((run) => run.state === "complete") && grade.state === "complete") return "complete";
507
+ return "partially-complete";
508
+ }
509
+
510
+ async function createGrade(group, runs, evidence) {
511
+ try {
512
+ return await gradeDeterministic(group, runs, evidence);
513
+ } catch (error) {
514
+ return gradeErrorReport(evidence, `deterministic grading failed: ${errorMessage(error)}`);
515
+ }
516
+ }
517
+
518
+ async function persistGrade(groupDirectory, grade) {
519
+ const artifact = "deterministic-grade.json";
520
+ try {
521
+ await writeJson(path.join(groupDirectory, artifact), grade);
522
+ return { grade, artifact, errors: [] };
523
+ } catch (error) {
524
+ const reason = `failed to persist ${artifact}: ${errorMessage(error)}`;
525
+ const failed = gradeErrorReport(grade.evidence, reason, grade);
526
+ const fallback = "deterministic-grade-error.json";
527
+ await writeJson(path.join(groupDirectory, fallback), failed);
528
+ return {
529
+ grade: failed,
530
+ artifact: fallback,
531
+ errors: [{ kind: "persistence", artifact, message: reason }],
532
+ };
533
+ }
534
+ }
535
+
536
+ async function persistGroupResult(groupDirectory, groupResult) {
537
+ const artifact = "group.json";
538
+ try {
539
+ await writeJson(path.join(groupDirectory, artifact), groupResult);
540
+ return groupResult;
541
+ } catch (error) {
542
+ const message = `failed to persist ${artifact}: ${errorMessage(error)}`;
543
+ const fallback = "group-error.json";
544
+ const failed = {
545
+ ...groupResult,
546
+ state: groupResult.state === "complete" ? "partially-complete" : groupResult.state,
547
+ artifacts: { ...groupResult.artifacts, group: fallback },
548
+ errors: [...groupResult.errors, { kind: "persistence", artifact, message }],
549
+ };
550
+ await writeJson(path.join(groupDirectory, fallback), failed);
551
+ return failed;
552
+ }
553
+ }
554
+
555
+ function gradeErrorReport(evidence, reason, grade = null) {
556
+ return {
557
+ schema_version: 1,
558
+ state: "grade-error",
559
+ evidence,
560
+ checks: grade?.checks ?? [],
561
+ comparisons: grade?.comparisons ?? [],
562
+ errors: [...(grade?.errors ?? []), { id: null, reason }],
563
+ };
564
+ }
565
+
566
+ function errorMessage(error) {
567
+ return error instanceof Error ? error.message : String(error);
568
+ }
569
+
570
+ async function executeVariant({
571
+ group,
572
+ variant,
573
+ root,
574
+ variantDirectory,
575
+ fixture,
576
+ runtime,
577
+ freeflow,
578
+ hostExtensions,
579
+ signal,
580
+ }) {
581
+ try {
582
+ const run =
583
+ armParticipants(group, variant) !== null ? runParticipants : group.type === "body" ? runBody : runDescription;
584
+ return await run({ group, variant, root, variantDirectory, fixture, runtime, freeflow, hostExtensions, signal });
585
+ } catch (error) {
586
+ if (error instanceof VariantSetupError) return invalidRun(group, variant, error.message);
587
+ return infrastructureFailedRun(group, variant, error);
588
+ } finally {
589
+ await hostAdapter(groupHost(group)).removeCredentials(variantDirectory);
590
+ }
591
+ }
592
+
593
+ async function persistRunOrFailure(variantDirectory, run) {
594
+ try {
595
+ return { run, file: await persistRun(variantDirectory, run) };
596
+ } catch (error) {
597
+ const failed = persistenceFailedRun(run, error);
598
+ const runFile = path.join(variantDirectory, "run.json");
599
+ await writeJson(runFile, {
600
+ ...failed,
601
+ transcript: failed.transcript ?? [],
602
+ artifacts: {
603
+ events: failed.process === undefined ? null : "events.jsonl",
604
+ final: null,
605
+ stderr: failed.process === undefined ? null : "stderr.log",
606
+ },
607
+ });
608
+ return { run: failed, file: runFile };
609
+ }
610
+ }
611
+
612
+ async function persistRun(variantDirectory, run) {
613
+ const transcript = run.transcript ?? [];
614
+ const response = run.response ?? "";
615
+ await writeJson(path.join(variantDirectory, "transcript.json"), transcript);
616
+ await writeText(path.join(variantDirectory, "final.md"), response === "" ? "" : `${response}\n`);
617
+ const runFile = path.join(variantDirectory, "run.json");
618
+ const hasProcessEvidence = run.process !== undefined;
619
+ const persisted = {
620
+ ...run,
621
+ transcript: "transcript.json",
622
+ artifacts: {
623
+ events: hasProcessEvidence ? "events.jsonl" : null,
624
+ final: "final.md",
625
+ stderr: hasProcessEvidence ? "stderr.log" : null,
626
+ context: run.contextObservationArtifact ? "context-observations.jsonl" : null,
627
+ },
628
+ };
629
+ if (Array.isArray(run.turns)) persisted.turns = externalizeTurnTranscripts(run.turns);
630
+ await writeJson(runFile, persisted);
631
+ return runFile;
632
+ }
633
+
634
+ function externalizeTurnTranscripts(turns) {
635
+ let offset = 0;
636
+ return turns.map((turn) => {
637
+ const length = Array.isArray(turn.transcript) ? turn.transcript.length : 0;
638
+ const transcript = { file: "transcript.json", start: offset, end: offset + length };
639
+ offset += length;
640
+ return { ...turn, transcript };
641
+ });
642
+ }
643
+
644
+ function notSelectedRun(group, variant) {
645
+ return {
646
+ schema_version: 1,
647
+ variant,
648
+ state: "not-selected",
649
+ evaluationType: group.type,
650
+ prompt: group.input.prompt ?? null,
651
+ prompts: group.input.turns ?? null,
652
+ activation: unavailableActivation(),
653
+ response: "",
654
+ transcript: [],
655
+ error: null,
656
+ };
657
+ }
658
+
659
+ function cancelledRun(group, variant) {
660
+ return {
661
+ schema_version: 1,
662
+ variant,
663
+ state: "cancelled",
664
+ evaluationType: group.type,
665
+ prompt: group.input.prompt ?? null,
666
+ prompts: group.input.turns ?? null,
667
+ activation: unavailableActivation(),
668
+ response: "",
669
+ transcript: [],
670
+ error: { kind: "cancellation", message: "Cancelled before subject execution" },
671
+ };
672
+ }
673
+
674
+ function invalidRun(group, variant, message) {
675
+ return {
676
+ schema_version: 1,
677
+ variant,
678
+ state: "invalid",
679
+ evaluationType: group.type,
680
+ prompt: group.input.prompt ?? null,
681
+ prompts: group.input.turns ?? null,
682
+ activation: unavailableActivation(),
683
+ response: "",
684
+ transcript: [],
685
+ error: { kind: "setup", message },
686
+ };
687
+ }
688
+
689
+ function persistenceFailedRun(run, error) {
690
+ return {
691
+ ...run,
692
+ state: "infrastructure-failed",
693
+ error: {
694
+ kind: "persistence",
695
+ message: error instanceof Error ? error.message : String(error),
696
+ cause: run.error ?? null,
697
+ },
698
+ };
699
+ }
700
+
701
+ function infrastructureFailedRun(group, variant, error) {
702
+ return {
703
+ schema_version: 1,
704
+ variant,
705
+ state: "infrastructure-failed",
706
+ evaluationType: group.type,
707
+ prompt: group.input.prompt ?? null,
708
+ prompts: group.input.turns ?? null,
709
+ activation: unavailableActivation(),
710
+ response: "",
711
+ transcript: [],
712
+ error: { kind: "infrastructure", message: error instanceof Error ? error.message : String(error) },
713
+ };
714
+ }
715
+
716
+ function unavailableActivation() {
717
+ return {
718
+ targetRead: null,
719
+ firstReadTurn: null,
720
+ readTurns: [],
721
+ successfulReadPaths: [],
722
+ };
723
+ }
724
+
725
+ // An unreadable run file leaves its identity unavailable instead of escaping the whole invocation.
726
+ async function runFileIdentity(file) {
727
+ try {
728
+ return await fileIdentity(file);
729
+ } catch (error) {
730
+ return { path: file, sha256: null, error: errorMessage(error) };
731
+ }
732
+ }