@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,241 @@
1
+ // How the evaluator launches Pi itself: the command-line arguments for a subject and the one-shot JSON-mode process
2
+ // that reports Pi's events. RPC sessions are in rpc.mjs.
3
+
4
+ import { spawn } from "node:child_process";
5
+ import { once } from "node:events";
6
+ import { createWriteStream } from "node:fs";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ import {
10
+ mergeUsage,
11
+ messageText,
12
+ NO_PROGRESS_MS,
13
+ pipeStream,
14
+ processGroupExists,
15
+ signalProcessTree,
16
+ TERMINATION_GRACE_MS,
17
+ waitForForcedKill,
18
+ writeStream,
19
+ } from "../../process.mjs";
20
+
21
+ const guardExtension = fileURLToPath(new URL("../../../pi-guard.mjs", import.meta.url));
22
+
23
+ /** The evaluator's guard extension, which every subject process (and a shell's confinement probe) loads first. */
24
+ export function guardExtensionPath() {
25
+ return guardExtension;
26
+ }
27
+ const commandToolExtension = fileURLToPath(new URL("../../../pi-command-tool.mjs", import.meta.url));
28
+ const containerRouteExtension = fileURLToPath(new URL("../../../pi-container-route.mjs", import.meta.url));
29
+
30
+ /**
31
+ * The extension that moves shell commands into a subject's container. It loads after every other extension, so
32
+ * theirs see each command as the model wrote it; the guard refuses container shell calls without it.
33
+ */
34
+ export function containerRouteExtensionPath() {
35
+ return containerRouteExtension;
36
+ }
37
+ const observerExtension = fileURLToPath(new URL("../../../pi-observer.mjs", import.meta.url));
38
+
39
+ export function piArguments(
40
+ group,
41
+ environment,
42
+ runtime,
43
+ mode,
44
+ observeContext,
45
+ sessionDirectory,
46
+ model,
47
+ freeflowEntry,
48
+ hostExtensions = [],
49
+ containerRoute = false,
50
+ ) {
51
+ const args = ["--mode", mode];
52
+ if (mode === "json") args.push("-p");
53
+ if (runtime.session) args.push("--session-dir", sessionDirectory);
54
+ else args.push("--no-session");
55
+ args.push("--no-extensions", "--extension", guardExtension);
56
+ // Provider extensions (such as a subscription's auth extension) load right after the guard.
57
+ for (const extension of hostExtensions) args.push("--extension", extension.path);
58
+ if (group.commands !== undefined) args.push("--extension", commandToolExtension);
59
+ if (freeflowEntry !== null) args.push("--extension", freeflowEntry);
60
+ for (const bundle of runtime.extensions) args.push("--extension", bundle.entry);
61
+ if (observeContext) args.push("--extension", observerExtension);
62
+ if (containerRoute) args.push("--extension", containerRouteExtension);
63
+ args.push("--no-skills", "--no-prompt-templates", "--no-themes", "--no-context-files", "--no-approve");
64
+ if (group.tools.length === 0) args.push("--no-tools");
65
+ else args.push("--tools", group.tools.join(","));
66
+ for (const skill of environment.skills) args.push("--skill", skill.path);
67
+ if (model?.model) args.push("--model", model.model);
68
+ if (model?.thinking) args.push("--thinking", model.thinking);
69
+ if (mode === "json") args.push(group.input.prompt);
70
+ return args;
71
+ }
72
+
73
+ export async function runPiProcess({ command, args, cwd, eventsFile, stderrFile, signal, environment }) {
74
+ const child = spawn(command, args, {
75
+ cwd,
76
+ detached: process.platform !== "win32",
77
+ env: environment,
78
+ shell: false,
79
+ stdio: ["ignore", "pipe", "pipe"],
80
+ });
81
+ const events = createWriteStream(eventsFile, { encoding: "utf8" });
82
+ const stderr = createWriteStream(stderrFile, { encoding: "utf8" });
83
+ const transcript = [];
84
+ const calls = new Map();
85
+ const toolActivity = [];
86
+ const successfulReads = [];
87
+ const parseErrors = [];
88
+ const protocolErrors = [];
89
+ let settled = false;
90
+ let response = "";
91
+ let usage = null;
92
+ let assistantError = null;
93
+ let observedModel = null;
94
+ let buffer = "";
95
+ let eventLine = 0;
96
+ const processGroupId = child.pid;
97
+ let watchdog;
98
+ let forcedKill;
99
+ /** @type {Promise<void> | null} */
100
+ let forcedKillPromise = null;
101
+ let terminationReason = null;
102
+
103
+ const resetWatchdog = () => {
104
+ clearTimeout(watchdog);
105
+ watchdog = setTimeout(() => requestTermination("no-progress-watchdog"), NO_PROGRESS_MS);
106
+ watchdog.unref();
107
+ };
108
+ const requestTermination = (reason) => {
109
+ if (terminationReason !== null) return;
110
+ terminationReason = reason;
111
+ signalProcessTree(processGroupId, child, "SIGTERM");
112
+ if (process.platform !== "win32") {
113
+ forcedKillPromise = new Promise((resolve) => {
114
+ forcedKill = setTimeout(() => {
115
+ signalProcessTree(processGroupId, child, "SIGKILL");
116
+ resolve();
117
+ }, TERMINATION_GRACE_MS);
118
+ });
119
+ }
120
+ };
121
+ const onAbort = () => requestTermination("cancelled");
122
+ if (signal?.aborted) onAbort();
123
+ else signal?.addEventListener("abort", onAbort, { once: true });
124
+ resetWatchdog();
125
+
126
+ const stderrTask = pipeStream(child.stderr, stderr, resetWatchdog);
127
+ const stdoutTask = (async () => {
128
+ for await (const chunk of child.stdout) {
129
+ resetWatchdog();
130
+ buffer += chunk.toString("utf8");
131
+ while (true) {
132
+ const newline = buffer.indexOf("\n");
133
+ if (newline === -1) break;
134
+ const line = buffer.slice(0, newline);
135
+ buffer = buffer.slice(newline + 1);
136
+ await writeStream(events, `${line}\n`);
137
+ observeLine(line.endsWith("\r") ? line.slice(0, -1) : line);
138
+ }
139
+ }
140
+ if (buffer.length > 0) {
141
+ await writeStream(events, buffer);
142
+ observeLine(buffer.endsWith("\r") ? buffer.slice(0, -1) : buffer);
143
+ }
144
+ events.end();
145
+ await once(events, "finish");
146
+ })();
147
+
148
+ function observeLine(line) {
149
+ eventLine += 1;
150
+ if (line.trim() === "") return;
151
+ let event;
152
+ try {
153
+ event = JSON.parse(line);
154
+ } catch {
155
+ parseErrors.push({ line: eventLine, reason: "invalid-json" });
156
+ return;
157
+ }
158
+ if (event.type === "extension_error") {
159
+ protocolErrors.push({
160
+ reason: "extension-error",
161
+ extensionPath: event.extensionPath ?? null,
162
+ event: event.event ?? null,
163
+ error: event.error ?? null,
164
+ });
165
+ requestTermination("protocol-error");
166
+ }
167
+ if (event.type === "agent_settled") settled = true;
168
+ if (event.type === "tool_execution_start") {
169
+ // Same shape as RPC turns record, so graders and the advisory reviewer see one-shot tool use too.
170
+ const activity = {
171
+ toolCallId: event.toolCallId ?? null,
172
+ toolName: event.toolName ?? null,
173
+ args: event.args ?? null,
174
+ completed: false,
175
+ isError: null,
176
+ };
177
+ toolActivity.push(activity);
178
+ calls.set(event.toolCallId, activity);
179
+ }
180
+ if (event.type === "tool_execution_end") {
181
+ const call = calls.get(event.toolCallId);
182
+ if (call) {
183
+ call.completed = true;
184
+ call.isError = event.isError === true;
185
+ }
186
+ if (!event.isError && call?.toolName === "read" && typeof call.args?.path === "string") {
187
+ successfulReads.push(call.args.path);
188
+ }
189
+ }
190
+ if (event.type === "message_end" && event.message) {
191
+ transcript.push(event.message);
192
+ if (event.message.role === "assistant") {
193
+ response = messageText(event.message);
194
+ usage = mergeUsage(usage, event.message.usage);
195
+ observedModel = {
196
+ provider: event.message.provider ?? null,
197
+ model: event.message.model ?? null,
198
+ };
199
+ assistantError =
200
+ event.message.stopReason === "error" || event.message.stopReason === "aborted"
201
+ ? (event.message.errorMessage ?? `assistant stopped with ${event.message.stopReason}`)
202
+ : null;
203
+ }
204
+ }
205
+ }
206
+
207
+ let exitCode = null;
208
+ let exitSignal = null;
209
+ try {
210
+ const [code, closedSignal] = await once(child, "close");
211
+ exitCode = code;
212
+ exitSignal = closedSignal;
213
+ await Promise.all([stdoutTask, stderrTask]);
214
+ } catch (error) {
215
+ requestTermination("process-error");
216
+ throw error;
217
+ } finally {
218
+ clearTimeout(watchdog);
219
+ if (forcedKillPromise !== null) {
220
+ if (processGroupExists(processGroupId)) await waitForForcedKill(forcedKillPromise);
221
+ else clearTimeout(forcedKill);
222
+ }
223
+ signal?.removeEventListener("abort", onAbort);
224
+ }
225
+
226
+ return {
227
+ exitCode,
228
+ signal: exitSignal,
229
+ settled,
230
+ assistantError,
231
+ model: observedModel,
232
+ terminationReason,
233
+ parseErrors,
234
+ protocolErrors,
235
+ successfulReads,
236
+ toolActivity,
237
+ transcript,
238
+ response,
239
+ usage,
240
+ };
241
+ }
@@ -15,7 +15,7 @@ import {
15
15
  waitForForcedKill,
16
16
  waitForProcessTreeExit,
17
17
  writeStream,
18
- } from "./process.mjs";
18
+ } from "../../process.mjs";
19
19
 
20
20
  const MAX_INCOMPLETE_FRAME_BYTES = 16 * 1024 * 1024;
21
21
 
@@ -28,7 +28,25 @@ export async function runRpcBodySession(options) {
28
28
  }
29
29
 
30
30
  class RpcSession {
31
- constructor({ command = "pi", args, cwd, eventsFile, stderrFile, signal, environment, afterTurn = null }) {
31
+ constructor({
32
+ command = "pi",
33
+ args,
34
+ cwd,
35
+ eventsFile,
36
+ stderrFile,
37
+ signal,
38
+ environment,
39
+ afterTurn = null,
40
+ nextPrompt = null,
41
+ settings = {},
42
+ resumeBefore = [],
43
+ }) {
44
+ this.settings = settings;
45
+ // Turn numbers before which the session is closed and resumed from its own file, as `pi --resume` would.
46
+ this.resumeBefore = new Set(resumeBefore);
47
+ // After the last declared prompt settles, `nextPrompt(turns)` may return one more prompt (a simulated user's
48
+ // reply), or null to end the session.
49
+ this.nextPrompt = nextPrompt;
32
50
  this.child = spawn(command, args, {
33
51
  cwd,
34
52
  detached: process.platform !== "win32",
@@ -47,6 +65,10 @@ class RpcSession {
47
65
  this.parseErrors = [];
48
66
  this.protocolErrors = [];
49
67
  this.activeTurn = null;
68
+ // A run Pi starts on its own while no prompt is in flight: an extension's message that starts a turn, such as
69
+ // Freeflow's notice that a background command exited or a monitor printed a line. Its activity joins the latest
70
+ // turn when it settles; the next prompt waits for it.
71
+ this.unprompted = null;
50
72
  this.decoder = new StringDecoder("utf8");
51
73
  this.buffer = "";
52
74
  this.incompleteFrameBytes = 0;
@@ -77,7 +99,7 @@ class RpcSession {
77
99
  }
78
100
 
79
101
  async run(prompts, targetPath = null) {
80
- let deliveredPrompts = prompts;
102
+ let deliveredPrompts = [...prompts];
81
103
  /** @type {any} */
82
104
  let delivery = { kind: "unavailable", turn: 1, targetPath };
83
105
  try {
@@ -88,12 +110,23 @@ class RpcSession {
88
110
  delivery = { kind: "explicit-skill-command", turn: 1, targetPath, command };
89
111
  }
90
112
  for (const [index, prompt] of deliveredPrompts.entries()) {
113
+ await this.unpromptedSettled();
91
114
  if (this.signal?.aborted || this.terminationReason !== null) break;
92
115
  if (delivery.kind === "unavailable") delivery = { kind: "natural-prompt", turn: 1, targetPath: null };
116
+ const resumed = this.resumeBefore.has(index + 1) ? await this.resume() : null;
93
117
  const turn = await this.runTurn(index + 1, prompt);
118
+ if (resumed !== null) turn.resumed = resumed;
94
119
  this.turns.push(turn);
95
120
  if (this.afterTurn !== null) turn.workspace = await this.afterTurn(turn.turn);
96
121
  if (turn.assistantError !== null) break;
122
+ if (this.nextPrompt !== null && index === deliveredPrompts.length - 1 && this.terminationReason === null) {
123
+ // A run a notice started right after the turn is part of what the user sees before replying.
124
+ await this.unpromptedSettled();
125
+ const next = await this.nextPrompt(this.turns);
126
+ // The simulated user's time is not the subject's lack of progress.
127
+ this.resetWatchdog();
128
+ if (typeof next === "string") deliveredPrompts.push(next);
129
+ }
97
130
  }
98
131
  } catch (error) {
99
132
  this.operationError = error;
@@ -104,6 +137,7 @@ class RpcSession {
104
137
  });
105
138
  this.requestTermination("protocol-error");
106
139
  }
140
+ await this.unpromptedSettled();
107
141
  } finally {
108
142
  if (!this.child.stdin.destroyed) this.child.stdin.end();
109
143
  }
@@ -114,9 +148,25 @@ class RpcSession {
114
148
  return { ...this.observation(deliveredPrompts, exitCode, exitSignal), delivery };
115
149
  }
116
150
 
151
+ // The subject's effective settings decide retry and compaction; the evaluator's defaults keep both off.
117
152
  async configure() {
118
- await this.sendCommand({ type: "set_auto_retry", enabled: false });
119
- await this.sendCommand({ type: "set_auto_compaction", enabled: false });
153
+ await this.sendCommand({ type: "set_auto_retry", enabled: this.settings.retry?.enabled === true });
154
+ await this.sendCommand({ type: "set_auto_compaction", enabled: this.settings.compaction?.enabled === true });
155
+ }
156
+
157
+ /**
158
+ * Closes the session and opens it again from its file: Pi tears the session down (`session_shutdown`) and starts
159
+ * it anew with `session_start` reason `resume`, as a user resuming it would.
160
+ */
161
+ async resume() {
162
+ /** @type {any} */
163
+ const state = await this.sendCommand({ type: "get_state" });
164
+ const sessionFile = state.data?.sessionFile;
165
+ if (typeof sessionFile !== "string" || sessionFile === "") throw new Error("Pi RPC session has no file to resume");
166
+ /** @type {any} */
167
+ const result = await this.sendCommand({ type: "switch_session", sessionPath: sessionFile });
168
+ if (result.data?.cancelled === true) throw new Error("Pi cancelled resuming the session");
169
+ return { sessionFile };
120
170
  }
121
171
 
122
172
  async resolveSkillCommand(targetPath) {
@@ -145,22 +195,31 @@ class RpcSession {
145
195
  resolveSettled = resolve;
146
196
  rejectSettled = reject;
147
197
  });
198
+ // An unprompted run still going when the prompt is sent becomes part of this turn.
199
+ const joined = this.unprompted;
200
+ this.unprompted = null;
148
201
  this.activeTurn = {
149
202
  turn: turnNumber,
150
203
  prompt,
151
- response: "",
152
- transcript: [],
153
- successfulReads: [],
154
- toolActivity: [],
155
- calls: new Map(),
204
+ response: joined?.response ?? "",
205
+ transcript: joined?.transcript ?? [],
206
+ successfulReads: joined?.successfulReads ?? [],
207
+ toolActivity: joined?.toolActivity ?? [],
208
+ calls: joined?.calls ?? new Map(),
156
209
  promptAccepted: false,
157
- usage: null,
158
- assistantError: null,
210
+ usage: joined?.usage ?? null,
211
+ assistantError: joined?.assistantError ?? null,
159
212
  settled: false,
160
213
  resolveSettled,
161
214
  rejectSettled,
162
215
  };
163
- await Promise.all([this.sendCommand({ type: "prompt", message: prompt }), settlement]);
216
+ joined?.resolveSettled();
217
+ // Pi refuses a prompt while it runs, unless told how to queue it. A run a notice starts as the prompt is sent
218
+ // takes the prompt as its follow-up, and the turn records both.
219
+ await Promise.all([
220
+ this.sendCommand({ type: "prompt", message: prompt, streamingBehavior: "followUp" }),
221
+ settlement,
222
+ ]);
164
223
  const result = finishTurn(this.activeTurn);
165
224
  this.activeTurn = null;
166
225
  return result;
@@ -238,6 +297,61 @@ class RpcSession {
238
297
  } else if (event.type === "response") this.observeResponse(event);
239
298
  else if (event.type === "agent_settled") this.observeSettlement();
240
299
  else if (this.activeTurn !== null) this.observeTurnEvent(event);
300
+ else if (event.type === "agent_start" || this.unprompted !== null) this.observeUnpromptedEvent(event);
301
+ }
302
+
303
+ /** Events of a run Pi started without a prompt; it opens with agent_start. */
304
+ observeUnpromptedEvent(event) {
305
+ if (this.unprompted === null) {
306
+ let resolveSettled;
307
+ const settled = new Promise((resolve) => {
308
+ resolveSettled = resolve;
309
+ });
310
+ this.unprompted = {
311
+ response: "",
312
+ transcript: [],
313
+ successfulReads: [],
314
+ toolActivity: [],
315
+ calls: new Map(),
316
+ usage: null,
317
+ assistantError: null,
318
+ settled,
319
+ resolveSettled,
320
+ };
321
+ }
322
+ this.observeTurnEvent(event, this.unprompted);
323
+ }
324
+
325
+ /** Resolves once no unprompted run is in progress. */
326
+ async unpromptedSettled() {
327
+ while (this.unprompted !== null && this.terminationReason === null) {
328
+ const { settled } = this.unprompted;
329
+ await Promise.race([settled, this.closed.catch(() => {})]);
330
+ if (this.unprompted?.settled === settled && this.terminationReason === null) {
331
+ // The process closed while the run was in progress; nothing more will arrive.
332
+ break;
333
+ }
334
+ }
335
+ }
336
+
337
+ /** An unprompted run settled: its activity joins the latest turn, as if that turn had continued. */
338
+ settleUnprompted() {
339
+ const run = this.unprompted;
340
+ this.unprompted = null;
341
+ const turn = this.turns.at(-1);
342
+ if (turn === undefined) {
343
+ run.resolveSettled();
344
+ this.failProtocol("unprompted-run-before-first-turn", { line: this.eventLine });
345
+ return;
346
+ }
347
+ turn.transcript.push(...run.transcript);
348
+ turn.successfulReads.push(...run.successfulReads);
349
+ turn.toolActivity.push(...run.toolActivity);
350
+ if (run.response !== "") turn.response = run.response;
351
+ turn.usage = mergeUsage(turn.usage, run.usage);
352
+ turn.assistantError ??= run.assistantError;
353
+ turn.unpromptedRuns = (turn.unpromptedRuns ?? 0) + 1;
354
+ run.resolveSettled();
241
355
  }
242
356
 
243
357
  observeResponse(event) {
@@ -268,6 +382,10 @@ class RpcSession {
268
382
  }
269
383
 
270
384
  observeSettlement() {
385
+ if (this.activeTurn === null && this.unprompted !== null) {
386
+ this.settleUnprompted();
387
+ return;
388
+ }
271
389
  if (this.activeTurn === null || this.activeTurn.settled) {
272
390
  this.failProtocol("unexpected-agent-settled", { line: this.eventLine });
273
391
  return;
@@ -276,7 +394,7 @@ class RpcSession {
276
394
  this.activeTurn.resolveSettled();
277
395
  }
278
396
 
279
- observeTurnEvent(event) {
397
+ observeTurnEvent(event, turn = this.activeTurn) {
280
398
  if (event.type === "tool_execution_start") {
281
399
  const activity = {
282
400
  toolCallId: event.toolCallId ?? null,
@@ -285,39 +403,39 @@ class RpcSession {
285
403
  completed: false,
286
404
  isError: null,
287
405
  };
288
- this.activeTurn.toolActivity.push(activity);
289
- if (typeof event.toolCallId === "string") this.activeTurn.calls.set(event.toolCallId, activity);
406
+ turn.toolActivity.push(activity);
407
+ if (typeof event.toolCallId === "string") turn.calls.set(event.toolCallId, activity);
290
408
  return;
291
409
  }
292
410
  if (event.type === "tool_execution_end") {
293
- this.observeToolEnd(event);
411
+ this.observeToolEnd(event, turn);
294
412
  return;
295
413
  }
296
- if (event.type === "message_end" && event.message) this.observeMessage(event.message);
414
+ if (event.type === "message_end" && event.message) this.observeMessage(event.message, turn);
297
415
  }
298
416
 
299
- observeToolEnd(event) {
300
- const activity = this.activeTurn.calls.get(event.toolCallId);
417
+ observeToolEnd(event, turn) {
418
+ const activity = turn.calls.get(event.toolCallId);
301
419
  if (!activity) return;
302
420
  activity.completed = true;
303
421
  activity.isError = event.isError === true;
304
422
  if (event.isError !== true && activity.toolName === "read" && typeof activity.args?.path === "string") {
305
- this.activeTurn.successfulReads.push(activity.args.path);
423
+ turn.successfulReads.push(activity.args.path);
306
424
  }
307
425
  }
308
426
 
309
- observeMessage(message) {
310
- this.activeTurn.transcript.push(message);
427
+ observeMessage(message, turn) {
428
+ turn.transcript.push(message);
311
429
  this.transcript.push(message);
312
430
  if (message.role !== "assistant") return;
313
- this.activeTurn.response = messageText(message);
314
- this.activeTurn.usage = mergeUsage(this.activeTurn.usage, message.usage);
431
+ turn.response = messageText(message);
432
+ turn.usage = mergeUsage(turn.usage, message.usage);
315
433
  this.observedModel = {
316
434
  provider: message.provider ?? null,
317
435
  model: message.model ?? null,
318
436
  };
319
437
  if (message.stopReason === "error" || message.stopReason === "aborted") {
320
- this.activeTurn.assistantError = message.errorMessage ?? `assistant stopped with ${message.stopReason}`;
438
+ turn.assistantError = message.errorMessage ?? `assistant stopped with ${message.stopReason}`;
321
439
  }
322
440
  }
323
441
 
@@ -0,0 +1,82 @@
1
+ import { execFile } from "node:child_process";
2
+ import { realpath } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { promisify } from "node:util";
5
+
6
+ const run = promisify(execFile);
7
+
8
+ /**
9
+ * The identity of the working-tree inputs a run reads: the definition root's HEAD commit, and which of the
10
+ * inputs differ from it (modified, untracked, or ignored). A run is canonical only when nothing differs, so
11
+ * every input it read can be recovered from that commit.
12
+ *
13
+ * @param {string} root the definition root
14
+ * @param {string[]} inputs absolute paths of files and directories the run reads from the working tree
15
+ * @returns {Promise<{commit: string | null, uncommitted: string[], repository: boolean}>}
16
+ */
17
+ export async function inputIdentity(root, inputs) {
18
+ const canonicalRoot = await realpath(root);
19
+ let toplevel;
20
+ try {
21
+ toplevel = await realpath((await git(canonicalRoot, ["rev-parse", "--show-toplevel"])).trim());
22
+ } catch {
23
+ return { commit: null, uncommitted: [], repository: false };
24
+ }
25
+ const commit = await git(toplevel, ["rev-parse", "--verify", "HEAD"])
26
+ .then((output) => output.trim())
27
+ .catch(() => null);
28
+ const paths = [];
29
+ for (const input of inputs) {
30
+ const resolved = await realpath(input).catch(() => path.resolve(input));
31
+ paths.push(path.relative(toplevel, resolved) || ".");
32
+ }
33
+ if (paths.length === 0) return { commit, uncommitted: [], repository: true };
34
+ const status = await git(toplevel, [
35
+ "status",
36
+ "--porcelain=v1",
37
+ "-z",
38
+ "--untracked-files=all",
39
+ "--ignored=matching",
40
+ "--",
41
+ ...paths,
42
+ ]);
43
+ const uncommitted = new Set();
44
+ const entries = status.split("\0").filter(Boolean);
45
+ for (let index = 0; index < entries.length; index += 1) {
46
+ const entry = entries[index];
47
+ const code = entry.slice(0, 2);
48
+ uncommitted.add(
49
+ path
50
+ .relative(canonicalRoot, path.join(toplevel, entry.slice(3)))
51
+ .split(path.sep)
52
+ .join("/"),
53
+ );
54
+ if (code[0] === "R" || code[0] === "C") index += 1; // a rename or copy carries its source path next
55
+ }
56
+ if (commit === null) {
57
+ for (const entry of paths) uncommitted.add(path.relative(canonicalRoot, path.join(toplevel, entry)));
58
+ }
59
+ return { commit, uncommitted: [...uncommitted].sort(), repository: true };
60
+ }
61
+
62
+ /** The message that refuses a canonical run whose inputs cannot be recovered from a commit. */
63
+ export function identityRefusal(identity) {
64
+ if (!identity.repository) {
65
+ return "the evaluation inputs are not in a Git repository, so no commit identifies them; run with --dry-run";
66
+ }
67
+ if (identity.uncommitted.length === 0) return null;
68
+ const shown = identity.uncommitted.slice(0, 10).join(", ");
69
+ const more = identity.uncommitted.length > 10 ? ` and ${identity.uncommitted.length - 10} more` : "";
70
+ return `uncommitted inputs: ${shown}${more}; commit them, or run with --dry-run`;
71
+ }
72
+
73
+ /** The installed host's version, as `pi --version` prints it. */
74
+ export async function installedHostVersion(command, environment) {
75
+ const { stdout } = await run(command, ["--version"], { env: environment, timeout: 30000 });
76
+ return stdout.trim().split(/\s+/).pop() ?? "";
77
+ }
78
+
79
+ async function git(cwd, args) {
80
+ const { stdout } = await run("git", args, { cwd, maxBuffer: 16 * 1024 * 1024 });
81
+ return stdout;
82
+ }