@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,178 @@
1
+ // A local relay between a Claude Code subject and Anthropic's API that records what each model request carried.
2
+ // Claude Code has no extension point that sees its requests, and it adds context of its own (an identity line, an
3
+ // environment note, reminders) even when the evaluator replaces its system prompt. So every subject's requests pass
4
+ // through here: the run keeps a host-context record of what Claude Code sent besides the evaluator's prompt, and,
5
+ // when a group checks context text, the same observations Pi's observer writes.
6
+
7
+ import { createHash } from "node:crypto";
8
+ import { appendFile, writeFile } from "node:fs/promises";
9
+ import http from "node:http";
10
+ import https from "node:https";
11
+
12
+ const DEFAULT_UPSTREAM = "https://api.anthropic.com";
13
+
14
+ function sha256(value) {
15
+ return createHash("sha256").update(value).digest("hex");
16
+ }
17
+
18
+ function blockText(block) {
19
+ if (typeof block === "string") return block;
20
+ if (!block || typeof block !== "object") return "";
21
+ if (block.type === "text" && typeof block.text === "string") return block.text;
22
+ if (block.type === "tool_result") {
23
+ if (typeof block.content === "string") return block.content;
24
+ if (Array.isArray(block.content)) return block.content.map(blockText).filter(Boolean).join("\n");
25
+ }
26
+ if (block.type === "image") return `[image:${block.source?.media_type ?? "unknown"}]`;
27
+ return "";
28
+ }
29
+
30
+ function contentText(content) {
31
+ if (typeof content === "string") return content;
32
+ if (!Array.isArray(content)) return "";
33
+ return content.map(blockText).filter(Boolean).join("\n");
34
+ }
35
+
36
+ function systemText(system) {
37
+ if (typeof system === "string") return system;
38
+ if (!Array.isArray(system)) return "";
39
+ return system.map(blockText).join("\n");
40
+ }
41
+
42
+ /**
43
+ * Starts the relay. `currentTurn()` names the session's turn when a request arrives. Context observations go to
44
+ * `observationPath` when it is set; the host-context record is written to `hostContextPath` on close.
45
+ *
46
+ * @param {{upstream?: string, observationPath: string | null, hostContextPath: string, currentTurn: () => number}} options
47
+ */
48
+ export async function startRecorder({ upstream = DEFAULT_UPSTREAM, observationPath, hostContextPath, currentTurn }) {
49
+ const target = new URL(upstream);
50
+ const transport = target.protocol === "http:" ? http : https;
51
+ const basePath = target.pathname.replace(/\/$/, "");
52
+ const requests = [];
53
+ const systems = {};
54
+ let first = null;
55
+ let providerRequest = 0;
56
+ let lastTurn = 0;
57
+ let requestInTurn = 0;
58
+ let writes = Promise.resolve();
59
+ const observe = (entry) => {
60
+ if (observationPath === null) return;
61
+ const line = `${JSON.stringify({ timestamp: new Date().toISOString(), ...entry })}\n`;
62
+ writes = writes.then(() => appendFile(observationPath, line, "utf8"));
63
+ };
64
+
65
+ const record = (request, body) => {
66
+ let parsed;
67
+ try {
68
+ parsed = JSON.parse(body.toString("utf8"));
69
+ } catch {
70
+ requests.push({ method: request.method, path: request.url, bytes: body.length });
71
+ return;
72
+ }
73
+ const system = systemText(parsed.system);
74
+ const systemSha = sha256(system);
75
+ systems[systemSha] = Array.isArray(parsed.system) ? parsed.system.map(blockText) : [system];
76
+ const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
77
+ requests.push({
78
+ method: request.method,
79
+ path: request.url,
80
+ model: parsed.model ?? null,
81
+ system: systemSha,
82
+ tools: Array.isArray(parsed.tools) ? parsed.tools.map((tool) => tool?.name ?? null) : [],
83
+ messages: messages.length,
84
+ roles: [...new Set(messages.map((message) => message?.role ?? null))],
85
+ });
86
+ if (!request.url.startsWith("/v1/messages") || request.url.includes("count_tokens")) return;
87
+ // The first request shows everything Claude Code put before the subject's first prompt.
88
+ first ??= {
89
+ system: systems[systemSha],
90
+ messages: messages.map((message) => ({ role: message?.role ?? null, text: contentText(message?.content) })),
91
+ };
92
+ const turn = currentTurn();
93
+ if (turn !== lastTurn) {
94
+ lastTurn = turn;
95
+ requestInTurn = 0;
96
+ observe({
97
+ turn,
98
+ kind: "context",
99
+ surface: "system-prompt",
100
+ prompt: null,
101
+ characters: system.length,
102
+ text: system,
103
+ systemPrompt: system,
104
+ });
105
+ }
106
+ providerRequest += 1;
107
+ requestInTurn += 1;
108
+ const normalized = messages.map((message) => ({
109
+ role: message?.role ?? null,
110
+ toolName: null,
111
+ text: contentText(message?.content),
112
+ }));
113
+ const text = normalized
114
+ .map((message) => message.text)
115
+ .filter(Boolean)
116
+ .join("\n");
117
+ observe({
118
+ turn,
119
+ kind: "context",
120
+ surface: "provider-context",
121
+ providerRequest,
122
+ requestInTurn,
123
+ characters: text.length,
124
+ text,
125
+ messages: normalized,
126
+ });
127
+ };
128
+
129
+ const server = http.createServer((request, response) => {
130
+ const chunks = [];
131
+ request.on("data", (chunk) => chunks.push(chunk));
132
+ request.on("end", () => {
133
+ const body = Buffer.concat(chunks);
134
+ if (request.method === "POST") record(request, body);
135
+ else requests.push({ method: request.method, path: request.url });
136
+ const headers = { ...request.headers, host: target.host };
137
+ const relayed = transport.request(
138
+ {
139
+ protocol: target.protocol,
140
+ hostname: target.hostname,
141
+ port: target.port || undefined,
142
+ path: `${basePath}${request.url}`,
143
+ method: request.method,
144
+ headers,
145
+ },
146
+ (upstreamResponse) => {
147
+ response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);
148
+ upstreamResponse.pipe(response);
149
+ },
150
+ );
151
+ relayed.on("error", (error) => {
152
+ if (!response.headersSent) response.writeHead(502, { "content-type": "text/plain" });
153
+ response.end(`relay error: ${error.message}`);
154
+ });
155
+ relayed.end(body);
156
+ });
157
+ });
158
+ await new Promise((resolve, reject) => {
159
+ server.once("error", reject);
160
+ server.listen(0, "127.0.0.1", resolve);
161
+ });
162
+
163
+ return {
164
+ url: `http://127.0.0.1:${server.address().port}`,
165
+ /** Stops the relay and writes the host-context record, with what Claude Code reported loading (`init`). */
166
+ async close({ init = null } = {}) {
167
+ await new Promise((resolve) => {
168
+ server.closeAllConnections?.();
169
+ server.close(() => resolve());
170
+ });
171
+ await writes;
172
+ await writeFile(
173
+ hostContextPath,
174
+ `${JSON.stringify({ schema_version: 1, upstream: target.origin, init, first, requests, systems }, null, 2)}\n`,
175
+ );
176
+ },
177
+ };
178
+ }
@@ -0,0 +1,494 @@
1
+ // A Claude Code process in headless stream-json mode: the evaluator writes each prompt as a user message on stdin,
2
+ // reads Claude Code's events from stdout, and sends the next prompt after each turn's `result`. Events are kept as
3
+ // Claude Code wrote them (events.jsonl) and normalized into the observation every host returns (see subject.mjs):
4
+ // tool calls under the evaluator's tool names, with Claude Code's own names and arguments kept beside them.
5
+
6
+ import { spawn } from "node:child_process";
7
+ import { once } from "node:events";
8
+ import { createWriteStream } from "node:fs";
9
+ import path from "node:path";
10
+ import { StringDecoder } from "node:string_decoder";
11
+
12
+ import {
13
+ mergeUsage,
14
+ messageText,
15
+ NO_PROGRESS_MS,
16
+ pipeStream,
17
+ processGroupExists,
18
+ signalProcessTree,
19
+ TERMINATION_GRACE_MS,
20
+ waitForForcedKill,
21
+ waitForProcessTreeExit,
22
+ writeStream,
23
+ } from "../../process.mjs";
24
+ import { startRecorder } from "./recorder.mjs";
25
+ import { readSkill, skillCommandPrompt } from "./skills.mjs";
26
+
27
+ // Claude Code's tool names, the evaluator's, and the argument holding the path. Glob is find when the group declared
28
+ // find, and ls otherwise.
29
+ const TOOL_NAMES = { Read: "read", Write: "write", Edit: "edit", Grep: "grep", Bash: "bash" };
30
+ const PATH_ARGUMENT = { Read: "file_path", Write: "file_path", Edit: "file_path", Glob: "path", Grep: "path" };
31
+
32
+ /** The evaluator's name and arguments for one of Claude Code's tool calls. */
33
+ export function evaluatorToolCall(name, input, declaredTools) {
34
+ const toolName =
35
+ name === "Glob"
36
+ ? declaredTools.includes("find") || !declaredTools.includes("ls")
37
+ ? "find"
38
+ : "ls"
39
+ : TOOL_NAMES[name];
40
+ const key = PATH_ARGUMENT[name];
41
+ let args = input ?? null;
42
+ if (key !== undefined && args !== null && typeof args === "object") {
43
+ const { [key]: value, ...rest } = args;
44
+ args = value === undefined ? rest : { path: value, ...rest };
45
+ }
46
+ return { toolName: toolName ?? name, args };
47
+ }
48
+
49
+ function argumentValue(args, flag) {
50
+ const index = args.indexOf(flag);
51
+ return index === -1 ? undefined : args[index + 1];
52
+ }
53
+
54
+ function usageFrom(result, previousCost) {
55
+ const usage = result.usage ?? {};
56
+ const cost = typeof result.total_cost_usd === "number" ? Math.max(0, result.total_cost_usd - previousCost) : 0;
57
+ return {
58
+ input: usage.input_tokens ?? 0,
59
+ output: usage.output_tokens ?? 0,
60
+ cacheRead: usage.cache_read_input_tokens ?? 0,
61
+ cacheWrite: usage.cache_creation_input_tokens ?? 0,
62
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: cost },
63
+ };
64
+ }
65
+
66
+ /** A persistent session over the declared prompts, then any `nextPrompt` replies. */
67
+ export async function runClaudeSession(options) {
68
+ return new ClaudeSession(options).run(options.prompts, options.targetPath ?? null);
69
+ }
70
+
71
+ /** One prompt, reported as a one-shot run: the first turn's reads and tool calls at the top level. */
72
+ export async function runClaudeOneShot(options) {
73
+ const observation = await new ClaudeSession(options).run(options.prompts, null);
74
+ const turn = observation.turns[0];
75
+ const { turns: _turns, delivery: _delivery, ...rest } = observation;
76
+ return { ...rest, successfulReads: turn?.successfulReads ?? [], toolActivity: turn?.toolActivity ?? [] };
77
+ }
78
+
79
+ class ClaudeSession {
80
+ constructor({
81
+ subject = null,
82
+ command = "claude",
83
+ args,
84
+ cwd,
85
+ eventsFile,
86
+ stderrFile,
87
+ signal,
88
+ environment,
89
+ afterTurn = null,
90
+ nextPrompt = null,
91
+ record = subject === null
92
+ ? null
93
+ : {
94
+ observationPath: subject.requiresContextObservation ? subject.contextObservationPath : null,
95
+ hostContextPath: path.join(path.dirname(eventsFile), "host-context.json"),
96
+ },
97
+ }) {
98
+ this.command = command;
99
+ this.args = args;
100
+ this.cwd = cwd;
101
+ this.environment = environment;
102
+ this.record = record;
103
+ this.signal = signal;
104
+ this.afterTurn = afterTurn;
105
+ this.nextPrompt = nextPrompt;
106
+ this.eventsFile = eventsFile;
107
+ this.stderrFile = stderrFile;
108
+ const tools = argumentValue(args, "--tools");
109
+ this.expectedTools = tools === undefined || tools === "" ? [] : tools.split(",");
110
+ this.declaredTools = JSON.parse(environment.SKILL_EVAL_ALLOWED_TOOLS ?? "[]");
111
+ this.turns = [];
112
+ this.transcript = [];
113
+ this.parseErrors = [];
114
+ this.protocolErrors = [];
115
+ this.activeTurn = null;
116
+ this.turnNumber = 0;
117
+ this.init = null;
118
+ this.observedModel = null;
119
+ this.reportedCost = 0;
120
+ this.terminationReason = null;
121
+ this.operationError = null;
122
+ this.decoder = new StringDecoder("utf8");
123
+ this.buffer = "";
124
+ this.eventLine = 0;
125
+ this.watchdog = undefined;
126
+ this.forcedKill = undefined;
127
+ /** @type {Promise<void> | null} */
128
+ this.forcedKillPromise = null;
129
+ }
130
+
131
+ async start() {
132
+ let environment = this.environment;
133
+ if (this.record !== null) {
134
+ this.recorder = await startRecorder({
135
+ upstream: this.environment.ANTHROPIC_BASE_URL,
136
+ observationPath: this.record.observationPath,
137
+ hostContextPath: this.record.hostContextPath,
138
+ currentTurn: () => this.turnNumber,
139
+ });
140
+ // The relay is on this machine, so a proxy the machine uses must not stand between them.
141
+ const noProxy = [this.environment.NO_PROXY, "127.0.0.1", "localhost"].filter(Boolean).join(",");
142
+ environment = { ...environment, ANTHROPIC_BASE_URL: this.recorder.url, NO_PROXY: noProxy, no_proxy: noProxy };
143
+ }
144
+ this.child = spawn(this.command, this.args, {
145
+ cwd: this.cwd,
146
+ detached: process.platform !== "win32",
147
+ env: environment,
148
+ shell: false,
149
+ stdio: ["pipe", "pipe", "pipe"],
150
+ });
151
+ this.processGroupId = this.child.pid;
152
+ this.events = createWriteStream(this.eventsFile, { encoding: "utf8" });
153
+ this.stderr = createWriteStream(this.stderrFile, { encoding: "utf8" });
154
+ this.onAbort = () => this.requestTermination("cancelled");
155
+ if (this.signal?.aborted) this.onAbort();
156
+ else this.signal?.addEventListener("abort", this.onAbort, { once: true });
157
+ this.resetWatchdog();
158
+ this.closed = new Promise((resolve, reject) => {
159
+ this.child.once("error", reject);
160
+ this.child.once("close", (exitCode, exitSignal) => {
161
+ this.activeTurn?.rejectSettled(new Error("Claude Code exited before the turn completed"));
162
+ resolve({ exitCode, exitSignal });
163
+ });
164
+ });
165
+ // A write to a process that already exited is reported by its exit, not as an unhandled error.
166
+ this.child.stdin.on("error", () => {});
167
+ this.stderrTask = pipeStream(this.child.stderr, this.stderr, () => this.resetWatchdog());
168
+ this.stdoutTask = this.readStdout();
169
+ }
170
+
171
+ async run(prompts, targetPath) {
172
+ let deliveredPrompts = [...prompts];
173
+ /** @type {any} */
174
+ let delivery = { kind: "unavailable", turn: 1, targetPath };
175
+ try {
176
+ if (targetPath !== null) {
177
+ // Claude Code's skill loader stays off, so the target skill arrives as Pi's skill command would expand it.
178
+ const skill = await readSkill(path.dirname(targetPath));
179
+ deliveredPrompts = [skillCommandPrompt(skill, prompts[0]), ...prompts.slice(1)];
180
+ delivery = { kind: "explicit-skill-command", turn: 1, targetPath, command: `skill:${skill.name}` };
181
+ }
182
+ await this.start();
183
+ for (let index = 0; index < deliveredPrompts.length; index += 1) {
184
+ if (this.signal?.aborted || this.terminationReason !== null) break;
185
+ if (delivery.kind === "unavailable") delivery = { kind: "natural-prompt", turn: 1, targetPath: null };
186
+ const turn = await this.runTurn(index + 1, deliveredPrompts[index]);
187
+ this.turns.push(turn);
188
+ if (this.afterTurn !== null) turn.workspace = await this.afterTurn(turn.turn);
189
+ if (turn.assistantError !== null) break;
190
+ if (this.nextPrompt !== null && index === deliveredPrompts.length - 1 && this.terminationReason === null) {
191
+ const next = await this.nextPrompt(this.turns);
192
+ // The simulated user's time is not the subject's lack of progress.
193
+ this.resetWatchdog();
194
+ if (typeof next === "string") deliveredPrompts.push(next);
195
+ }
196
+ }
197
+ } catch (error) {
198
+ this.operationError = error;
199
+ if (this.terminationReason === null) {
200
+ this.protocolErrors.push({
201
+ reason: "operation-failed",
202
+ message: error instanceof Error ? error.message : String(error),
203
+ });
204
+ if (this.child !== undefined) this.requestTermination("protocol-error");
205
+ }
206
+ } finally {
207
+ if (this.child !== undefined && !this.child.stdin.destroyed) this.child.stdin.end();
208
+ }
209
+
210
+ const { exitCode, exitSignal } =
211
+ this.child === undefined ? { exitCode: null, exitSignal: null } : await this.finish();
212
+ this.finalizeInterruptedTurn();
213
+ this.recordUnclassifiedProcessError();
214
+ return { ...this.observation(deliveredPrompts, exitCode, exitSignal), delivery };
215
+ }
216
+
217
+ async runTurn(turnNumber, prompt) {
218
+ let resolveSettled;
219
+ let rejectSettled;
220
+ const settlement = new Promise((resolve, reject) => {
221
+ resolveSettled = resolve;
222
+ rejectSettled = reject;
223
+ });
224
+ // Awaited below; a rejection that arrives while the prompt is still being written is handled there.
225
+ settlement.catch(() => {});
226
+ this.turnNumber = turnNumber;
227
+ this.activeTurn = {
228
+ turn: turnNumber,
229
+ prompt,
230
+ response: "",
231
+ transcript: [],
232
+ messages: new Map(),
233
+ successfulReads: [],
234
+ toolActivity: [],
235
+ calls: new Map(),
236
+ promptAccepted: false,
237
+ usage: null,
238
+ assistantError: null,
239
+ settled: false,
240
+ resolveSettled,
241
+ rejectSettled,
242
+ };
243
+ const entry = { role: "user", content: prompt };
244
+ this.activeTurn.transcript.push(entry);
245
+ this.transcript.push(entry);
246
+ this.resetWatchdog();
247
+ const message = { type: "user", message: { role: "user", content: prompt } };
248
+ await writeStream(this.child.stdin, `${JSON.stringify(message)}\n`);
249
+ await settlement;
250
+ const result = finishTurn(this.activeTurn);
251
+ this.activeTurn = null;
252
+ return result;
253
+ }
254
+
255
+ async readStdout() {
256
+ for await (const chunk of this.child.stdout) {
257
+ this.resetWatchdog();
258
+ this.buffer += this.decoder.write(chunk);
259
+ while (true) {
260
+ const newline = this.buffer.indexOf("\n");
261
+ if (newline === -1) break;
262
+ const line = this.buffer.slice(0, newline);
263
+ this.buffer = this.buffer.slice(newline + 1);
264
+ await writeStream(this.events, `${line}\n`);
265
+ this.observeLine(line.endsWith("\r") ? line.slice(0, -1) : line);
266
+ }
267
+ }
268
+ this.buffer += this.decoder.end();
269
+ if (this.buffer.length > 0) {
270
+ await writeStream(this.events, this.buffer);
271
+ this.parseErrors.push({ line: this.eventLine + 1, reason: "unterminated-record" });
272
+ }
273
+ this.events.end();
274
+ await once(this.events, "finish");
275
+ }
276
+
277
+ observeLine(line) {
278
+ this.eventLine += 1;
279
+ if (line.trim() === "") return;
280
+ let event;
281
+ try {
282
+ event = JSON.parse(line);
283
+ } catch {
284
+ this.parseErrors.push({ line: this.eventLine, reason: "invalid-json" });
285
+ this.failProtocol("invalid-json", { line: this.eventLine });
286
+ return;
287
+ }
288
+ if (event.type === "system" && event.subtype === "init") this.observeInit(event);
289
+ else if (this.activeTurn === null) return;
290
+ else if (event.type === "assistant") this.observeAssistant(event.message);
291
+ else if (event.type === "user") this.observeUser(event.message);
292
+ else if (event.type === "result") this.observeResult(event);
293
+ }
294
+
295
+ // Claude Code reports what it loaded; anything beyond the declared tools, or any MCP server, voids the run.
296
+ observeInit(event) {
297
+ this.init = {
298
+ version: event.claude_code_version ?? null,
299
+ model: event.model ?? null,
300
+ tools: event.tools ?? [],
301
+ mcpServers: event.mcp_servers ?? [],
302
+ skills: event.skills ?? [],
303
+ slashCommands: event.slash_commands ?? [],
304
+ agents: event.agents ?? [],
305
+ plugins: event.plugins ?? [],
306
+ permissionMode: event.permissionMode ?? null,
307
+ apiKeySource: event.apiKeySource ?? null,
308
+ outputStyle: event.output_style ?? null,
309
+ };
310
+ const tools = Array.isArray(event.tools) ? event.tools : [];
311
+ const extra = tools.filter((tool) => !this.expectedTools.includes(tool));
312
+ const missing = this.expectedTools.filter((tool) => !tools.includes(tool));
313
+ if (extra.length > 0 || missing.length > 0) this.failProtocol("host-tools-differ", { extra, missing });
314
+ if (Array.isArray(event.mcp_servers) && event.mcp_servers.length > 0) {
315
+ this.failProtocol("undeclared-mcp-servers", { servers: event.mcp_servers.map((server) => server?.name ?? null) });
316
+ }
317
+ }
318
+
319
+ // Claude Code reports each content block of an assistant message as its own event; they are one message.
320
+ observeAssistant(message) {
321
+ if (!message || typeof message !== "object") return;
322
+ const turn = this.activeTurn;
323
+ turn.promptAccepted = true;
324
+ this.observedModel = { provider: "anthropic", model: message.model ?? null };
325
+ let entry = typeof message.id === "string" ? turn.messages.get(message.id) : undefined;
326
+ if (entry === undefined) {
327
+ entry = { role: "assistant", id: message.id ?? null, model: message.model ?? null, content: [] };
328
+ if (typeof message.id === "string") turn.messages.set(message.id, entry);
329
+ turn.transcript.push(entry);
330
+ this.transcript.push(entry);
331
+ }
332
+ entry.stopReason = message.stop_reason ?? entry.stopReason ?? null;
333
+ for (const block of Array.isArray(message.content) ? message.content : []) {
334
+ entry.content.push(block);
335
+ if (block?.type !== "tool_use") continue;
336
+ const { toolName, args } = evaluatorToolCall(block.name, block.input, this.declaredTools);
337
+ const activity = {
338
+ toolCallId: block.id ?? null,
339
+ toolName,
340
+ args,
341
+ hostToolName: block.name ?? null,
342
+ hostArgs: block.input ?? null,
343
+ completed: false,
344
+ isError: null,
345
+ };
346
+ turn.toolActivity.push(activity);
347
+ if (typeof block.id === "string") turn.calls.set(block.id, activity);
348
+ }
349
+ }
350
+
351
+ observeUser(message) {
352
+ if (!message || typeof message !== "object") return;
353
+ const turn = this.activeTurn;
354
+ const entry = { role: "user", content: message.content };
355
+ turn.transcript.push(entry);
356
+ this.transcript.push(entry);
357
+ for (const block of Array.isArray(message.content) ? message.content : []) {
358
+ if (block?.type !== "tool_result") continue;
359
+ const activity = turn.calls.get(block.tool_use_id);
360
+ if (!activity) continue;
361
+ activity.completed = true;
362
+ activity.isError = block.is_error === true;
363
+ if (!activity.isError && activity.toolName === "read" && typeof activity.args?.path === "string") {
364
+ turn.successfulReads.push(activity.args.path);
365
+ }
366
+ }
367
+ }
368
+
369
+ observeResult(event) {
370
+ const turn = this.activeTurn;
371
+ if (turn.settled) {
372
+ this.failProtocol("unexpected-result", { line: this.eventLine });
373
+ return;
374
+ }
375
+ turn.promptAccepted = true;
376
+ turn.usage = usageFrom(event, this.reportedCost);
377
+ if (typeof event.total_cost_usd === "number") this.reportedCost = event.total_cost_usd;
378
+ const lastAssistant = turn.transcript.filter((message) => message.role === "assistant").at(-1);
379
+ turn.response = typeof event.result === "string" ? event.result : lastAssistant ? messageText(lastAssistant) : "";
380
+ if (event.is_error === true || event.subtype !== "success") {
381
+ turn.assistantError =
382
+ (typeof event.result === "string" && event.result !== "" ? event.result : null) ??
383
+ (event.api_error_status ? `API error ${event.api_error_status}` : `Claude Code stopped with ${event.subtype}`);
384
+ }
385
+ turn.settled = true;
386
+ turn.resolveSettled();
387
+ }
388
+
389
+ failProtocol(reason, details = {}) {
390
+ this.protocolErrors.push({ reason, ...details });
391
+ this.activeTurn?.rejectSettled(new Error(`Claude Code protocol error: ${reason}`));
392
+ this.requestTermination("protocol-error");
393
+ }
394
+
395
+ resetWatchdog() {
396
+ clearTimeout(this.watchdog);
397
+ this.watchdog = setTimeout(() => this.requestTermination("no-progress-watchdog"), NO_PROGRESS_MS);
398
+ this.watchdog.unref();
399
+ }
400
+
401
+ requestTermination(reason) {
402
+ if (this.terminationReason !== null) return;
403
+ this.terminationReason = reason;
404
+ this.activeTurn?.rejectSettled(new Error(`Claude Code session terminated: ${reason}`));
405
+ if (this.child === undefined) return;
406
+ signalProcessTree(this.processGroupId, this.child, "SIGTERM");
407
+ if (process.platform !== "win32") {
408
+ this.forcedKillPromise = new Promise((resolve) => {
409
+ this.forcedKill = setTimeout(() => {
410
+ signalProcessTree(this.processGroupId, this.child, "SIGKILL");
411
+ resolve();
412
+ }, TERMINATION_GRACE_MS);
413
+ });
414
+ }
415
+ }
416
+
417
+ async finish() {
418
+ let exitCode = null;
419
+ let exitSignal = null;
420
+ try {
421
+ const closed = await this.closed;
422
+ exitCode = closed.exitCode;
423
+ exitSignal = closed.exitSignal;
424
+ await Promise.all([this.stdoutTask, this.stderrTask]);
425
+ } catch (error) {
426
+ this.operationError ??= error;
427
+ this.requestTermination("process-error");
428
+ await Promise.allSettled([this.stdoutTask, this.stderrTask]);
429
+ } finally {
430
+ clearTimeout(this.watchdog);
431
+ if (this.forcedKillPromise !== null) {
432
+ if (processGroupExists(this.processGroupId)) await waitForForcedKill(this.forcedKillPromise);
433
+ else clearTimeout(this.forcedKill);
434
+ } else if (processGroupExists(this.processGroupId)) {
435
+ signalProcessTree(this.processGroupId, this.child, "SIGTERM");
436
+ await waitForProcessTreeExit(this.processGroupId, this.child);
437
+ }
438
+ this.signal?.removeEventListener("abort", this.onAbort);
439
+ await this.recorder?.close({ init: this.init });
440
+ }
441
+ return { exitCode, exitSignal };
442
+ }
443
+
444
+ finalizeInterruptedTurn() {
445
+ const turn = this.activeTurn;
446
+ if (turn === null) return;
447
+ const observed = turn.promptAccepted || turn.settled || turn.transcript.length > 0 || turn.toolActivity.length > 0;
448
+ if (observed) this.turns.push(finishTurn(turn));
449
+ this.activeTurn = null;
450
+ }
451
+
452
+ recordUnclassifiedProcessError() {
453
+ if (this.operationError === null || this.terminationReason === "cancelled" || this.protocolErrors.length > 0) {
454
+ return;
455
+ }
456
+ this.protocolErrors.push({
457
+ reason: "process-error",
458
+ message: this.operationError instanceof Error ? this.operationError.message : String(this.operationError),
459
+ });
460
+ }
461
+
462
+ observation(prompts, exitCode, exitSignal) {
463
+ return {
464
+ exitCode,
465
+ signal: exitSignal,
466
+ settled: this.turns.length === prompts.length && this.turns.every((turn) => turn.settled),
467
+ assistantError: this.turns.find((turn) => turn.assistantError !== null)?.assistantError ?? null,
468
+ model: this.observedModel,
469
+ terminationReason: this.terminationReason,
470
+ parseErrors: this.parseErrors,
471
+ protocolErrors: this.protocolErrors,
472
+ turns: this.turns,
473
+ transcript: this.transcript,
474
+ response: this.turns.at(-1)?.response ?? "",
475
+ usage: this.turns.reduce((total, turn) => mergeUsage(total, turn.usage), null),
476
+ host: this.init,
477
+ };
478
+ }
479
+ }
480
+
481
+ function finishTurn(turn) {
482
+ return {
483
+ turn: turn.turn,
484
+ prompt: turn.prompt,
485
+ response: turn.response,
486
+ transcript: turn.transcript,
487
+ successfulReads: turn.successfulReads,
488
+ toolActivity: turn.toolActivity,
489
+ promptAccepted: turn.promptAccepted,
490
+ usage: turn.usage,
491
+ assistantError: turn.assistantError,
492
+ settled: turn.settled,
493
+ };
494
+ }