@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,81 @@
1
+ // Declared skills on Claude Code. Its own skill loader would also find bundled and user skills, so the evaluator
2
+ // keeps it off and delivers declared skills the way Pi's evaluated subjects see them: a listing of each skill's
3
+ // name, description and SKILL.md location in the system prompt, and, for a body run's target, Pi's exact skill
4
+ // command expansion as the first prompt.
5
+
6
+ import { readFile } from "node:fs/promises";
7
+ import path from "node:path";
8
+
9
+ import { escapeXml } from "../../../guard-rules.mjs";
10
+
11
+ const FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
12
+
13
+ function scalar(value) {
14
+ const trimmed = value.trim();
15
+ if (trimmed.startsWith('"')) return JSON.parse(trimmed);
16
+ if (trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1).replaceAll("''", "'");
17
+ return trimmed;
18
+ }
19
+
20
+ /**
21
+ * A declared skill's SKILL.md: its frontmatter `name`, `description` and `disable-model-invocation`, and its body.
22
+ * Only one-line scalars are read; a skill whose name or description this cannot read is refused, never guessed.
23
+ *
24
+ * @param {string} directory the materialized skill directory
25
+ */
26
+ export async function readSkill(directory) {
27
+ const filePath = path.join(directory, "SKILL.md");
28
+ const contents = await readFile(filePath, "utf8");
29
+ const match = FRONTMATTER.exec(contents);
30
+ if (match === null) throw new Error(`skill has no frontmatter: ${filePath}`);
31
+ const fields = {};
32
+ for (const line of match[1].split(/\r?\n/)) {
33
+ const field = /^([A-Za-z][\w-]*):(.*)$/.exec(line);
34
+ if (field !== null) fields[field[1]] = field[2];
35
+ }
36
+ const read = (key) => {
37
+ if (fields[key] === undefined) return undefined;
38
+ try {
39
+ return scalar(fields[key]);
40
+ } catch {
41
+ return undefined;
42
+ }
43
+ };
44
+ const name = read("name");
45
+ const description = read("description");
46
+ if (!name || !description || /^[>|]/.test(name) || /^[>|]/.test(description)) {
47
+ throw new Error(`skill needs a one-line name and description the Claude Code adapter can read: ${filePath}`);
48
+ }
49
+ return {
50
+ name,
51
+ description,
52
+ filePath,
53
+ baseDir: directory,
54
+ disableModelInvocation: read("disable-model-invocation") === "true",
55
+ body: contents.slice(match[0].length).trim(),
56
+ };
57
+ }
58
+
59
+ /** The `<available_skills>` listing for the system prompt, as Pi writes it; empty when no skill may be invoked. */
60
+ export function skillListing(skills) {
61
+ const listed = skills.filter((skill) => !skill.disableModelInvocation);
62
+ if (listed.length === 0) return "";
63
+ const lines = ["<available_skills>"];
64
+ for (const skill of listed) {
65
+ lines.push(
66
+ " <skill>",
67
+ ` <name>${escapeXml(skill.name)}</name>`,
68
+ ` <description>${escapeXml(skill.description)}</description>`,
69
+ ` <location>${escapeXml(skill.filePath)}</location>`,
70
+ " </skill>",
71
+ );
72
+ }
73
+ lines.push("</available_skills>");
74
+ return lines.join("\n");
75
+ }
76
+
77
+ /** The prompt Pi delivers for `/skill:<name> <prompt>`, so an explicit invocation reads the same on both hosts. */
78
+ export function skillCommandPrompt(skill, prompt) {
79
+ const block = `<skill name="${skill.name}" location="${skill.filePath}">\nReferences are relative to ${skill.baseDir}.\n\n${skill.body}\n</skill>`;
80
+ return prompt ? `${block}\n\n${prompt}` : block;
81
+ }
@@ -0,0 +1,31 @@
1
+ // Evaluation hosts. A host is the agent program that runs a subject's model and tools: Pi or Claude Code. The evaluator's
2
+ // core is host-neutral; each host's adapter implements the same interface:
3
+ //
4
+ // - name, label, command; version(environment): the installed host's version.
5
+ // - resolveExtensions(declared, { deferSources }): declared host extensions, found among the installed ones.
6
+ // - refreshLogins(providers): make every login a batch uses valid before it starts.
7
+ // - effectiveSettings(declared): the evaluator's host defaults with declared settings winning.
8
+ // - prepareIsolation(directory, model, { settings }) -> { environment, evidence, loginDirectory }: a private home,
9
+ // temp and host configuration for one process, with only the declared provider's login, and the directory that
10
+ // login lives in (the shell probes plant a marker there); removeCredentials(directory) after.
11
+ // - prepareLaunch(context) -> { args, environment }: one subject's arguments and the host's own variables.
12
+ // - runOneShot(options), runSession(options): run a subject and return the normalized observation (see subject.mjs).
13
+ // - modelCall(directory, prompt, options): one tool-less call for a judge, reviewer or simulated user.
14
+ // - probeShell(options): run the shell tier's confinement probes through the host (see shell.mjs).
15
+ //
16
+ // Names a definition may use are in names.mjs, which definitions.mjs reads without loading any adapter.
17
+
18
+ import { claudeCodeHost } from "./claude-code/index.mjs";
19
+ import { piHost } from "./pi/index.mjs";
20
+
21
+ const ADAPTERS = new Map([
22
+ [piHost.name, piHost],
23
+ [claudeCodeHost.name, claudeCodeHost],
24
+ ]);
25
+
26
+ /** The adapter for a host name; an unknown name is an error, never a fallback to Pi. */
27
+ export function hostAdapter(name) {
28
+ const adapter = ADAPTERS.get(name);
29
+ if (adapter === undefined) throw new Error(`unknown evaluation host: ${name}`);
30
+ return adapter;
31
+ }
@@ -0,0 +1,3 @@
1
+ // The hosts a definition may name in `host.name`. Each has an adapter in hosts/; definitions.mjs reads this list
2
+ // without loading the adapters.
3
+ export const EVALUATION_HOSTS = new Set(["pi", "claude-code"]);
@@ -0,0 +1,173 @@
1
+ // Pi's part of the shell tier's confinement probes (shell.mjs): the arm's own Pi, with its extensions and the
2
+ // evaluator's guard, runs every probe as a bash call from a local scripted model, and reports what each returned.
3
+
4
+ import { readFile, writeFile } from "node:fs/promises";
5
+ import http from "node:http";
6
+ import path from "node:path";
7
+
8
+ import { baseProcessEnvironment } from "../../process.mjs";
9
+ import { containerRouteExtensionPath, guardExtensionPath, runPiProcess } from "./process.mjs";
10
+
11
+ const PROBE_PROVIDER = "skill-eval-probe";
12
+ const PROBE_MODEL = "confinement";
13
+
14
+ /**
15
+ * Runs the probes through Pi in JSON mode. `guard` is the guard's environment for the probe workspace; `isolation`
16
+ * is the probe's prepared isolation, whose agent directory gets the scripted model.
17
+ *
18
+ * @returns {Promise<{observation: any, launchError: string | null, results: Map<string, {ran: boolean, isError: boolean, output: string}>}>}
19
+ */
20
+ export async function probeShell({ probes, workspace, isolation, extensions, guard, eventsFile, stderrFile, signal }) {
21
+ const model = await startModelStub(probes);
22
+ try {
23
+ const agent = path.join(isolation.evidence.root, "agent");
24
+ await writeFile(
25
+ path.join(agent, "models.json"),
26
+ `${JSON.stringify({ providers: { [PROBE_PROVIDER]: { baseUrl: model.baseUrl, api: "openai-completions", apiKey: "probe", models: [{ id: PROBE_MODEL }] } } }, null, 2)}\n`,
27
+ );
28
+ const environment = {
29
+ ...baseProcessEnvironment(),
30
+ PI_SKIP_VERSION_CHECK: "1",
31
+ PI_TELEMETRY: "0",
32
+ ...guard,
33
+ ...isolation.environment,
34
+ };
35
+ const args = ["--mode", "json", "-p", "--no-session", "--no-extensions", "--extension", guardExtensionPath()];
36
+ for (const extension of extensions) args.push("--extension", extension.path);
37
+ // A container shell's commands reach the container through the route extension, last, as in a subject.
38
+ if (guard.SKILL_EVAL_CONTAINER) args.push("--extension", containerRouteExtensionPath());
39
+ args.push(
40
+ "--no-skills",
41
+ "--no-prompt-templates",
42
+ "--no-themes",
43
+ "--no-context-files",
44
+ "--no-approve",
45
+ "--tools",
46
+ "bash",
47
+ "--model",
48
+ `${PROBE_PROVIDER}/${PROBE_MODEL}`,
49
+ "Run each confinement probe with bash, exactly as given.",
50
+ );
51
+ let observation = null;
52
+ let launchError = null;
53
+ try {
54
+ observation = await runPiProcess({
55
+ command: "pi",
56
+ args,
57
+ cwd: workspace,
58
+ eventsFile,
59
+ stderrFile,
60
+ signal,
61
+ environment,
62
+ });
63
+ } catch (error) {
64
+ launchError = error instanceof Error ? error.message : String(error);
65
+ }
66
+ // Whatever Pi reported before a launch error still counts.
67
+ return { observation, launchError, results: await toolResults(eventsFile) };
68
+ } finally {
69
+ await model.close();
70
+ }
71
+ }
72
+
73
+ /** Each probe's tool result from Pi's JSON events, by tool call ID. */
74
+ async function toolResults(eventsFile) {
75
+ const results = new Map();
76
+ const contents = await readFile(eventsFile, "utf8").catch(() => "");
77
+ for (const line of contents.split("\n")) {
78
+ if (line.trim() === "") continue;
79
+ let event;
80
+ try {
81
+ event = JSON.parse(line);
82
+ } catch {
83
+ continue;
84
+ }
85
+ if (event.type !== "tool_execution_end" || typeof event.toolCallId !== "string") continue;
86
+ const content = Array.isArray(event.result?.content) ? event.result.content : [];
87
+ results.set(event.toolCallId, {
88
+ ran: true,
89
+ isError: event.isError === true,
90
+ output: content
91
+ .filter((part) => part?.type === "text")
92
+ .map((part) => part.text)
93
+ .join(""),
94
+ });
95
+ }
96
+ return results;
97
+ }
98
+
99
+ /**
100
+ * A local OpenAI-compatible chat-completions endpoint that answers the first request with every probe as a bash
101
+ * tool call, and any request carrying tool results with a short final answer. No model is called.
102
+ */
103
+ function startModelStub(probes) {
104
+ return new Promise((resolve, reject) => {
105
+ const server = http.createServer((request, response) => {
106
+ let body = "";
107
+ request.setEncoding("utf8");
108
+ request.on("data", (chunk) => {
109
+ body += chunk;
110
+ });
111
+ request.on("end", () => {
112
+ let parsed = {};
113
+ try {
114
+ parsed = JSON.parse(body || "{}");
115
+ } catch {
116
+ // Answered as a first request.
117
+ }
118
+ const followUp = Array.isArray(parsed.messages) && parsed.messages.some((message) => message?.role === "tool");
119
+ const message = followUp
120
+ ? { role: "assistant", content: "Probes finished." }
121
+ : {
122
+ role: "assistant",
123
+ content: null,
124
+ tool_calls: probes.map((probe, index) => ({
125
+ index,
126
+ id: probe.id,
127
+ type: "function",
128
+ function: { name: "bash", arguments: JSON.stringify({ command: probe.command }) },
129
+ })),
130
+ };
131
+ const finish = followUp ? "stop" : "tool_calls";
132
+ const base = { id: "probe", created: 0, model: parsed.model ?? PROBE_MODEL };
133
+ const usage = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 };
134
+ if (parsed.stream !== true) {
135
+ response.writeHead(200, { "content-type": "application/json" });
136
+ response.end(
137
+ JSON.stringify({
138
+ ...base,
139
+ object: "chat.completion",
140
+ choices: [
141
+ {
142
+ index: 0,
143
+ message: { ...message, tool_calls: message.tool_calls?.map(({ index: _index, ...call }) => call) },
144
+ finish_reason: finish,
145
+ },
146
+ ],
147
+ usage,
148
+ }),
149
+ );
150
+ return;
151
+ }
152
+ response.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache" });
153
+ const send = (chunk) =>
154
+ response.write(`data: ${JSON.stringify({ ...base, object: "chat.completion.chunk", ...chunk })}\n\n`);
155
+ send({ choices: [{ index: 0, delta: message, finish_reason: null }] });
156
+ send({ choices: [{ index: 0, delta: {}, finish_reason: finish }] });
157
+ send({ choices: [], usage });
158
+ response.end("data: [DONE]\n\n");
159
+ });
160
+ });
161
+ server.once("error", reject);
162
+ server.listen(0, "127.0.0.1", () => {
163
+ resolve({
164
+ baseUrl: `http://127.0.0.1:${server.address().port}/v1`,
165
+ close: () =>
166
+ new Promise((done) => {
167
+ server.closeAllConnections?.();
168
+ server.close(() => done());
169
+ }),
170
+ });
171
+ });
172
+ });
173
+ }
@@ -0,0 +1,148 @@
1
+ // Pi-specific knowledge the evaluator needs outside a subject process: where the user's Pi agent directory
2
+ // is, how installed Pi packages are found, and how a stored OAuth login is kept fresh. Kept in one module so a
3
+ // later host adapter has one place to grow from (D-007).
4
+
5
+ import { execFile } from "node:child_process";
6
+ import { createHash } from "node:crypto";
7
+ import { mkdir, readFile, rm, stat } from "node:fs/promises";
8
+ import os from "node:os";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { promisify } from "node:util";
12
+
13
+ const run = promisify(execFile);
14
+ const REFRESH_HELPER = fileURLToPath(new URL("../../../pi-login-refresh.mjs", import.meta.url));
15
+ const LOCK_STALE_MS = 2 * 60 * 1000;
16
+ const LOCK_WAIT_MS = 90 * 1000;
17
+
18
+ /**
19
+ * Pi settings the evaluator uses unless a configuration's host.settings declares otherwise: automatic retry and
20
+ * compaction stay off, so a provider error or a compaction never happens silently inside a measured run.
21
+ */
22
+ export const EVALUATOR_PI_SETTINGS = Object.freeze({ retry: { enabled: false }, compaction: { enabled: false } });
23
+
24
+ /** The settings a subject actually runs with: the evaluator's defaults, with every declared setting winning. */
25
+ export function effectivePiSettings(declared = {}) {
26
+ const merge = (base, overlay) => {
27
+ const result = structuredClone(base);
28
+ for (const [key, value] of Object.entries(overlay)) {
29
+ const isObject = (entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry);
30
+ result[key] = isObject(result[key]) && isObject(value) ? merge(result[key], value) : structuredClone(value);
31
+ }
32
+ return result;
33
+ };
34
+ return merge(EVALUATOR_PI_SETTINGS, declared);
35
+ }
36
+
37
+ /** The user's Pi agent directory: an explicit override for the evaluator, then Pi's own variable, then its default. */
38
+ export function piAgentDirectory() {
39
+ return (
40
+ process.env.SKILL_EVAL_CREDENTIALS_DIR ||
41
+ process.env.PI_CODING_AGENT_DIR ||
42
+ path.join(process.env.HOME || os.homedir(), ".pi", "agent")
43
+ );
44
+ }
45
+
46
+ export async function readJsonObject(file) {
47
+ try {
48
+ const value = JSON.parse(await readFile(file, "utf8"));
49
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Finds each declared package extension among the user's installed Pi packages (`<agent dir>/npm/node_modules`),
57
+ * by exact name and version. A missing package or another version refuses the run. An extension built from source
58
+ * (`source` or `path`, see build-source.mjs) is built per group into its resources, so with `deferSources` it stays
59
+ * in its declared position as `{ pending: <declared entry> }`; without it, it is refused.
60
+ *
61
+ * @param {Array<any>} declared
62
+ * @param {{deferSources?: boolean}} [options]
63
+ */
64
+ export async function resolveHostExtensions(declared, { deferSources = false } = {}) {
65
+ const root = path.join(piAgentDirectory(), "npm", "node_modules");
66
+ const resolved = [];
67
+ for (const extension of declared) {
68
+ if (!Object.hasOwn(extension, "package")) {
69
+ if (!deferSources) throw new Error("host.extensions built from source are supported only in arm configurations");
70
+ resolved.push({ pending: extension });
71
+ continue;
72
+ }
73
+ const directory = path.join(root, ...extension.package.split("/"));
74
+ const manifest = await readJsonObject(path.join(directory, "package.json"));
75
+ if (manifest === null) {
76
+ throw new Error(`host.extensions: ${extension.package} is not installed in Pi (looked in ${root})`);
77
+ }
78
+ if (manifest.version !== extension.version) {
79
+ throw new Error(
80
+ `host.extensions: ${extension.package} is ${manifest.version} in Pi, but the definition declares ${extension.version}`,
81
+ );
82
+ }
83
+ resolved.push({ path: directory, package: `${extension.package}@${extension.version}` });
84
+ }
85
+ return resolved;
86
+ }
87
+
88
+ /** Minutes left on a provider's stored OAuth login, or null when the login is not OAuth or not stored. */
89
+ export async function loginMinutesLeft(provider) {
90
+ const login = (await readJsonObject(path.join(piAgentDirectory(), "auth.json")))?.[provider];
91
+ if (!login || login.type !== "oauth" || typeof login.expires !== "number") return null;
92
+ return Math.floor((login.expires - Date.now()) / 60000);
93
+ }
94
+
95
+ /**
96
+ * Makes a provider's stored OAuth login valid for at least `target` minutes when it has fewer than `threshold`
97
+ * left, by asking the installed Pi to refresh it in the user's own agent directory. One evaluator process
98
+ * refreshes at a time; the others wait and then reread. API-key and absent logins are left alone.
99
+ *
100
+ * @returns {Promise<number | null>} minutes left afterwards, or null when the login is not OAuth
101
+ */
102
+ export async function ensureLogin(provider, { threshold, target }) {
103
+ const before = await loginMinutesLeft(provider);
104
+ if (before === null || before >= threshold) return before;
105
+ const authPath = path.join(piAgentDirectory(), "auth.json");
106
+ await withLock(authPath, async () => {
107
+ const current = await loginMinutesLeft(provider);
108
+ if (current !== null && current >= threshold) return;
109
+ const helper = process.env.SKILL_EVAL_LOGIN_REFRESH || REFRESH_HELPER;
110
+ try {
111
+ await run(process.execPath, [helper, authPath, provider, String(target)], { timeout: 60000 });
112
+ } catch (error) {
113
+ const detail = error?.stderr?.trim() || (error instanceof Error ? error.message : String(error));
114
+ throw new Error(`refreshing the ${provider} login failed (log in again in Pi): ${detail}`);
115
+ }
116
+ });
117
+ const after = await loginMinutesLeft(provider);
118
+ if (after === null || after < threshold) {
119
+ throw new Error(`the ${provider} login has ${after ?? 0} minutes left after a refresh; log in again in Pi`);
120
+ }
121
+ return after;
122
+ }
123
+
124
+ async function withLock(authPath, work) {
125
+ const lock = path.join(
126
+ os.tmpdir(),
127
+ `skill-eval-login-${createHash("sha256").update(authPath).digest("hex").slice(0, 16)}.lock`,
128
+ );
129
+ await mkdir(path.dirname(lock), { recursive: true });
130
+ const deadline = Date.now() + LOCK_WAIT_MS;
131
+ for (;;) {
132
+ try {
133
+ await mkdir(lock);
134
+ break;
135
+ } catch (error) {
136
+ if (error?.code !== "EEXIST") throw error;
137
+ const info = await stat(lock).catch(() => null);
138
+ if (info && Date.now() - info.mtimeMs > LOCK_STALE_MS) await rm(lock, { recursive: true, force: true });
139
+ if (Date.now() > deadline) throw new Error(`timed out waiting for another login refresh (${lock})`);
140
+ await new Promise((resolve) => setTimeout(resolve, 200));
141
+ }
142
+ }
143
+ try {
144
+ return await work();
145
+ } finally {
146
+ await rm(lock, { recursive: true, force: true });
147
+ }
148
+ }
@@ -0,0 +1,70 @@
1
+ // The Pi host adapter: everything the evaluator does that depends on Pi, behind the interface in ../index.mjs.
2
+
3
+ import { installedHostVersion } from "../../identity.mjs";
4
+ import { baseProcessEnvironment } from "../../process.mjs";
5
+ import { probeShell } from "./confinement.mjs";
6
+ import { effectivePiSettings, ensureLogin, resolveHostExtensions } from "./host.mjs";
7
+ import { prepareIsolation, removeCopiedCredentials, TARGET_MINUTES } from "./isolation.mjs";
8
+ import { launchModel } from "./model-call.mjs";
9
+ import { piArguments, runPiProcess } from "./process.mjs";
10
+ import { runRpcBodySession } from "./rpc.mjs";
11
+
12
+ export const piHost = Object.freeze({
13
+ name: "pi",
14
+ label: "Pi",
15
+ command: "pi",
16
+
17
+ /** The installed Pi's version, as `pi --version` prints it. */
18
+ version: (environment = baseProcessEnvironment()) => installedHostVersion("pi", environment),
19
+
20
+ resolveExtensions: resolveHostExtensions,
21
+
22
+ /** Makes each provider's stored OAuth login valid for the target window, once, before a batch. */
23
+ async refreshLogins(providers) {
24
+ for (const provider of providers)
25
+ await ensureLogin(provider, { threshold: TARGET_MINUTES, target: TARGET_MINUTES });
26
+ },
27
+
28
+ effectiveSettings: effectivePiSettings,
29
+ prepareIsolation,
30
+ removeCredentials: removeCopiedCredentials,
31
+
32
+ /** Pi's arguments and its own environment switches for one subject. */
33
+ async prepareLaunch({
34
+ group,
35
+ variant,
36
+ environment,
37
+ runtime,
38
+ mode,
39
+ observeContext,
40
+ sessionDirectory,
41
+ model,
42
+ freeflowEntry,
43
+ hostExtensions,
44
+ }) {
45
+ return {
46
+ args: piArguments(
47
+ group,
48
+ environment,
49
+ runtime,
50
+ mode,
51
+ observeContext,
52
+ sessionDirectory,
53
+ model,
54
+ freeflowEntry,
55
+ hostExtensions,
56
+ group.variants[variant]?.shell?.container !== undefined,
57
+ ),
58
+ environment: { PI_SKIP_VERSION_CHECK: "1", PI_TELEMETRY: "0" },
59
+ };
60
+ },
61
+
62
+ /** One prompt in JSON mode; the prompt is the last argument. */
63
+ runOneShot: runPiProcess,
64
+
65
+ /** A persistent RPC session over the declared prompts, then any `nextPrompt` replies. */
66
+ runSession: runRpcBodySession,
67
+
68
+ modelCall: launchModel,
69
+ probeShell,
70
+ });
@@ -0,0 +1,81 @@
1
+ import { mkdir, rm, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+
4
+ import { ensureLogin, piAgentDirectory, readJsonObject } from "./host.mjs";
5
+
6
+ // A copied OAuth login must outlast the process using it: a refresh inside the copy would rotate the token
7
+ // there and leave the user's own login holding a revoked one. So the login is refreshed centrally, in the
8
+ // user's agent directory, whenever it has less than SUBJECT_MINUTES left, to at least TARGET_MINUTES.
9
+ export const SUBJECT_MINUTES = 30;
10
+ export const TARGET_MINUTES = 120;
11
+
12
+ /**
13
+ * Creates a private home, temp directory and Pi agent directory for one host process, and the environment
14
+ * that points the process at them. Only the declared provider's login is copied in, never another's, after
15
+ * a central refresh if it was close to expiring; the declared Pi settings become the agent directory's
16
+ * settings.json. The parent's HOME, TMPDIR, XDG directories and Pi settings are not visible.
17
+ *
18
+ * @param {string} directory where the isolation root is created
19
+ * @param {string | null} model the declared `provider/model`, or null
20
+ * @param {{settings?: Record<string, unknown>}} [options]
21
+ * @returns {Promise<{environment: Record<string, string>, evidence: any, loginDirectory: string}>}
22
+ */
23
+ export async function prepareIsolation(directory, model, { settings = {} } = {}) {
24
+ const root = path.join(directory, "isolation");
25
+ const home = path.join(root, "home");
26
+ const agent = path.join(root, "agent");
27
+ const tmp = path.join(root, "tmp");
28
+ for (const entry of [home, agent, tmp]) await mkdir(entry, { recursive: true });
29
+ if (Object.keys(settings).length > 0) {
30
+ await writeFile(path.join(agent, "settings.json"), `${JSON.stringify(settings, null, 2)}\n`);
31
+ }
32
+
33
+ const provider = typeof model === "string" && model.includes("/") ? model.split("/")[0] : null;
34
+ const source = piAgentDirectory();
35
+ const credentials = [];
36
+ if (provider !== null) {
37
+ // The caller reports a refresh failure as an invalid run, before any host process starts.
38
+ await ensureLogin(provider, { threshold: SUBJECT_MINUTES, target: TARGET_MINUTES });
39
+ const login = (await readJsonObject(path.join(source, "auth.json")))?.[provider];
40
+ if (login && typeof login === "object") {
41
+ await writeFile(path.join(agent, "auth.json"), `${JSON.stringify({ [provider]: login })}\n`, { mode: 0o600 });
42
+ credentials.push({ file: "auth.json", provider, type: typeof login.type === "string" ? login.type : null });
43
+ }
44
+ const models = await readJsonObject(path.join(source, "models.json"));
45
+ const custom = models?.providers?.[provider];
46
+ if (custom && typeof custom === "object") {
47
+ await writeFile(path.join(agent, "models.json"), `${JSON.stringify({ providers: { [provider]: custom } })}\n`, {
48
+ mode: 0o600,
49
+ });
50
+ credentials.push({ file: "models.json", provider, type: "provider" });
51
+ }
52
+ }
53
+
54
+ return {
55
+ environment: {
56
+ HOME: home,
57
+ TMPDIR: tmp,
58
+ TMP: tmp,
59
+ TEMP: tmp,
60
+ XDG_CONFIG_HOME: path.join(home, ".config"),
61
+ XDG_DATA_HOME: path.join(home, ".local", "share"),
62
+ XDG_CACHE_HOME: path.join(home, ".cache"),
63
+ PI_CODING_AGENT_DIR: agent,
64
+ },
65
+ evidence: { root, provider, credentials, settings },
66
+ // Where the host keeps its login: the confinement probe plants a marker here that the shell must not read.
67
+ loginDirectory: agent,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Deletes the copied login and model entries once the process has exited, so no copy of a credential
73
+ * stays in the run's evidence. Safe to call when nothing was copied.
74
+ *
75
+ * @param {string} directory the directory passed to prepareIsolation
76
+ */
77
+ export async function removeCopiedCredentials(directory) {
78
+ for (const file of ["auth.json", "models.json"]) {
79
+ await rm(path.join(directory, "isolation", "agent", file), { force: true });
80
+ }
81
+ }
@@ -0,0 +1,79 @@
1
+ // One model call through Pi that is not a subject: a judge, a reviewer, or a simulated user. It runs without tools,
2
+ // skills, context files or session, in its own isolated home and agent directory, with the provider's login copied in
3
+ // and removed afterward.
4
+
5
+ import { mkdir, rm } from "node:fs/promises";
6
+ import path from "node:path";
7
+
8
+ import { writeText } from "../../evidence.mjs";
9
+ import { baseProcessEnvironment } from "../../process.mjs";
10
+ import { effectivePiSettings } from "./host.mjs";
11
+ import { prepareIsolation, removeCopiedCredentials } from "./isolation.mjs";
12
+ import { runPiProcess } from "./process.mjs";
13
+
14
+ /**
15
+ * Starts one model call on a prompt in its own directory, which keeps the prompt, events, final response and stderr.
16
+ *
17
+ * @param {string} directory replaced on every call
18
+ * @param {string} prompt
19
+ * @param {{model: string, thinking: string | null, extensions: Array<{path: string}>, settings: object, signal?: AbortSignal, role?: string}} options
20
+ * @returns {Promise<{response: string | null, errors: string[], usage: any, isolation: any}>}
21
+ */
22
+ export async function launchModel(directory, prompt, options) {
23
+ const { model, thinking, extensions, settings, signal, role = "reviewer" } = options;
24
+ await rm(directory, { recursive: true, force: true });
25
+ await mkdir(directory, { recursive: true });
26
+ await writeText(path.join(directory, "prompt.md"), prompt);
27
+
28
+ const args = [
29
+ "--mode",
30
+ "json",
31
+ "-p",
32
+ "--no-session",
33
+ "--no-extensions",
34
+ ...extensions.flatMap((extension) => ["--extension", extension.path]),
35
+ "--no-skills",
36
+ "--no-prompt-templates",
37
+ "--no-themes",
38
+ "--no-context-files",
39
+ "--no-approve",
40
+ "--no-tools",
41
+ "--model",
42
+ model,
43
+ ];
44
+ if (thinking !== null) args.push("--thinking", thinking);
45
+ args.push(prompt);
46
+ let isolation;
47
+ try {
48
+ // The evaluator's Pi defaults (retry and compaction off) apply here as for subjects; declared settings win.
49
+ isolation = await prepareIsolation(directory, model, { settings: effectivePiSettings(settings) });
50
+ } catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ return { response: null, errors: [message], usage: null, isolation: null };
53
+ }
54
+ const observation = await runPiProcess({
55
+ command: "pi",
56
+ args,
57
+ cwd: directory,
58
+ eventsFile: path.join(directory, "events.jsonl"),
59
+ stderrFile: path.join(directory, "stderr.log"),
60
+ signal,
61
+ environment: {
62
+ ...baseProcessEnvironment(),
63
+ PWD: directory,
64
+ PI_SKIP_VERSION_CHECK: "1",
65
+ PI_TELEMETRY: "0",
66
+ ...isolation.environment,
67
+ },
68
+ });
69
+ await removeCopiedCredentials(directory);
70
+ await writeText(path.join(directory, "final.md"), `${observation.response}\n`);
71
+
72
+ const errors = [];
73
+ if (observation.exitCode !== 0 || !observation.settled || observation.assistantError !== null) {
74
+ errors.push(
75
+ `${role} did not complete: exit=${observation.exitCode} settled=${observation.settled} error=${observation.assistantError}`,
76
+ );
77
+ }
78
+ return { response: observation.response, errors, usage: observation.usage, isolation: isolation.evidence };
79
+ }