@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
@@ -1,1034 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { access, readFile } from "node:fs/promises";
4
- import { join } from "node:path";
5
- import { fixture } from "../fixtures/routing-native.js";
6
- import { replay } from "../../dist/cognitive-routing-v2/state.js";
7
- import { RoutingRuntime } from "../../dist/cognitive-routing-v2/runtime.js";
8
-
9
- for (const recoveryWorker of ["executor", "helper"]) {
10
- const cognitiveRouting =
11
- recoveryWorker === "helper"
12
- ? {
13
- enabled: true,
14
- delegation: "helper",
15
- projection: true,
16
- profiles: {
17
- coordinator: { provider: "openai", model: "gpt-4o", thinking: "off" },
18
- helper: { provider: "openai", model: "gpt-4.1-mini", thinking: "off" },
19
- },
20
- }
21
- : undefined;
22
- test(
23
- `attached ${recoveryWorker} recovery reuses omitted evidence, gates exact native reads, and blocks returned work`,
24
- { timeout: 30000 },
25
- async () => {
26
- let assignmentId, baseReportId, baseReportRevision, omittedRef, supplementRef, recoveryRef, cwd;
27
- const originalInvoke = RoutingRuntime.prototype.invoke;
28
- const replayed = new Set();
29
- RoutingRuntime.prototype.invoke = async function (name, id, input, signal, ctx) {
30
- const intercepted =
31
- name === "freeflow_unit" && input.operation === "recover"
32
- ? { ...input, request: `${input.request} [accepted]` }
33
- : name === "freeflow_return" && input.operation === "supplement"
34
- ? { ...input, report: `${input.report} [accepted]` }
35
- : input;
36
- const first = await originalInvoke.call(this, name, id, intercepted, signal, ctx);
37
- const key = `${name}:${input.operation}`;
38
- if (
39
- ((name === "freeflow_unit" && input.operation === "recover") ||
40
- (name === "freeflow_return" && input.operation === "supplement")) &&
41
- !replayed.has(key)
42
- ) {
43
- replayed.add(key);
44
- this.receipts.clear();
45
- const repeated = await originalInvoke.call(this, name, id, intercepted, signal, ctx);
46
- assert.deepEqual(repeated, first, "same accepted operation returns the recorded receipt");
47
- this.receipts.clear();
48
- const changed = await originalInvoke.call(
49
- this,
50
- name,
51
- id,
52
- { ...intercepted, [input.operation === "recover" ? "request" : "report"]: "CHANGED_PAYLOAD" },
53
- signal,
54
- ctx,
55
- );
56
- assert.equal(changed.details.code, "operation_conflict");
57
- }
58
- return first;
59
- };
60
- try {
61
- await fixture(
62
- async (n, body, manager) => {
63
- if (n === 1)
64
- return [
65
- { name: "freeflow_delegate", args: { operation: "assign", contract: "Read two files and report." } },
66
- ];
67
- if (n === 2) {
68
- assert.equal(replay(manager.getBranch()).profile, recoveryWorker);
69
- return [
70
- { name: "read", args: { path: "evidence.txt" } },
71
- { name: "read", args: { path: "unselected.txt" } },
72
- ];
73
- }
74
- if (n === 3) {
75
- const reads = manager.getBranch().filter((e) => e.message?.toolName === "read" && !e.message.isError);
76
- omittedRef = `ctx:${reads[1].id}`;
77
- return [
78
- { name: "freeflow_project", args: { operation: "add", refs: [`ctx:${reads[0].id}`] } },
79
- {
80
- name: "freeflow_return",
81
- args: { operation: "submit", report: "BASE_REPORT_UNCHANGED_41", outcome: "completed" },
82
- },
83
- ];
84
- }
85
- if (n === 4) {
86
- const state = replay(manager.getBranch());
87
- assignmentId = state.assignmentId;
88
- baseReportId = state.assignments.get(assignmentId).returnHandoffId;
89
- baseReportRevision = state.handoffs.get(baseReportId).reportRevision;
90
- const wire = JSON.stringify(body);
91
- assert.match(wire, /BASE_REPORT_UNCHANGED_41/);
92
- assert.match(wire, /EXACT_EVIDENCE_BODY_81/);
93
- assert.doesNotMatch(wire, /UNSELECTED_PRIVATE_BODY_93/);
94
- return [
95
- {
96
- name: "freeflow_unit",
97
- args: {
98
- operation: "recover",
99
- request: "Select the omitted result and read the approved third file only.",
100
- paths: ["recovery.txt"],
101
- },
102
- },
103
- ];
104
- }
105
- if (n === 5) {
106
- assert.equal(body.model, "gpt-4.1-mini");
107
- assert.equal(replay(manager.getBranch()).profile, recoveryWorker);
108
- assert.match(
109
- JSON.stringify(body),
110
- /Select the omitted result and read the approved third file only\. \[accepted\]/,
111
- );
112
- return [
113
- { name: "read", args: { path: "recovery.txt" } },
114
- { name: "read", args: { path: "@recovery.txt" } },
115
- { name: "read", args: { path: "evidence.txt" } },
116
- { name: "write", args: { path: "recovery-write.txt", content: "forbidden" } },
117
- { name: "bash", args: { command: "touch recovery-bash.txt" } },
118
- ];
119
- }
120
- if (n === 6) {
121
- const recent = manager
122
- .getBranch()
123
- .filter((e) => ["read", "write", "bash"].includes(e.message?.toolName))
124
- .slice(-5);
125
- const allowed = recent.find(
126
- (e) =>
127
- e.message.toolName === "read" &&
128
- !e.message.isError &&
129
- JSON.stringify(e.message).includes("FRESH_RECOVERY_BODY_57"),
130
- );
131
- assert.ok(allowed, "the exact approved native read executes");
132
- assert.equal(
133
- recent.filter((e) => e !== allowed).every((e) => e.message.isError),
134
- true,
135
- );
136
- await assert.rejects(access(join(cwd, "recovery-write.txt")));
137
- await assert.rejects(access(join(cwd, "recovery-bash.txt")));
138
- assert.equal(await readFile(join(cwd, "@recovery.txt"), "utf8"), "LITERAL_AT_FILE_BODY_68");
139
- assert.equal(
140
- recent.some((e) => JSON.stringify(e.message).includes("LITERAL_AT_FILE_BODY_68")),
141
- false,
142
- "Pi never reaches either @-transformed or literal resource for a rejected alias",
143
- );
144
- return [
145
- {
146
- name: "freeflow_project",
147
- args: { operation: "add", refs: [omittedRef, `ctx:${allowed.id}`, "ctx:missing"] },
148
- },
149
- {
150
- name: "freeflow_return",
151
- args: { operation: "supplement", report: "RECOVERY_SUPPLEMENT_73", outcome: "completed" },
152
- },
153
- ];
154
- }
155
- if (n === 7) return [{ name: "read", args: { path: "recovery.txt" } }];
156
- if (n === 8) {
157
- const postSupplement = manager
158
- .getBranch()
159
- .filter((e) => e.message?.toolName === "read")
160
- .at(-1);
161
- assert.equal(postSupplement.message.isError, true, "a saved supplement ends recovery read permission");
162
- assert.equal(postSupplement.message.content[0].text, "worker_task_phase_ended");
163
- return [
164
- {
165
- name: "freeflow_project",
166
- args: {
167
- operation: "remove",
168
- refs: ["ctx:missing"],
169
- reason: "Fixture removes the unresolved request.",
170
- },
171
- },
172
- { name: "freeflow_return", args: { operation: "retry" } },
173
- ];
174
- }
175
- assert.equal(body.model, "gpt-4o");
176
- const wire = JSON.stringify(body);
177
- const state = replay(manager.getBranch());
178
- if (n === 14) {
179
- assert.equal(state.assessment.view, "suspended");
180
- assert.equal(state.assessment.suspensionReason, "user-attention");
181
- assert.doesNotMatch(wire, /EXACT_EVIDENCE_BODY_81/);
182
- assert.match(wire, /NEW_USER_ATTENTION_29/);
183
- return [{ name: "freeflow_unit", args: { operation: "assess" } }];
184
- }
185
- for (const value of [
186
- "BASE_REPORT_UNCHANGED_41",
187
- "RECOVERY_SUPPLEMENT_73 [accepted]",
188
- "EXACT_EVIDENCE_BODY_81",
189
- "UNSELECTED_PRIVATE_BODY_93",
190
- "FRESH_RECOVERY_BODY_57",
191
- ])
192
- assert.ok(wire.includes(value), `missing ${value}`);
193
- assert.match(wire, new RegExp(`producer: ${recoveryWorker}`));
194
- if (n === 15) {
195
- assert.equal(state.assessment.view, "active");
196
- return [];
197
- }
198
- assert.equal(state.assignmentId, assignmentId);
199
- assert.equal(state.assignments.get(assignmentId).state, "returned");
200
- assert.equal(state.assignments.get(assignmentId).returnHandoffId, baseReportId);
201
- assert.equal(state.handoffs.get(baseReportId).text, "BASE_REPORT_UNCHANGED_41");
202
- assert.equal(state.handoffs.get(baseReportId).outcome, "completed");
203
- assert.equal(state.handoffs.get(baseReportId).reportRevision, baseReportRevision);
204
- assert.equal(state.assessment.handoffId, baseReportId);
205
- assert.equal(state.assessment.view, "active");
206
- assert.equal(state.recoveryId, undefined);
207
- const completedRecovery = [...state.recoveries.values()].at(-1);
208
- assert.equal(completedRecovery.state, "completed");
209
- supplementRef = `supplement:${completedRecovery.id}:${completedRecovery.supplementRevision}`;
210
- recoveryRef = `recovery:${completedRecovery.id}`;
211
- assert.equal(
212
- state.selections.get(assignmentId).selected.includes(omittedRef),
213
- true,
214
- "the originally omitted result is selected",
215
- );
216
- for (const marker of ["EXACT_EVIDENCE_BODY_81", "UNSELECTED_PRIVATE_BODY_93"])
217
- assert.equal(
218
- manager
219
- .getBranch()
220
- .filter(
221
- (e) =>
222
- e.message?.toolName === "read" &&
223
- !e.message.isError &&
224
- JSON.stringify(e.message).includes(marker),
225
- ).length,
226
- 1,
227
- `${marker} was not replayed`,
228
- );
229
- if (n === 9)
230
- return [{ name: "freeflow_unit", args: { operation: "inspect", view: "detail", ref: supplementRef } }];
231
- if (n === 10) {
232
- const detail = manager
233
- .getBranch()
234
- .filter((e) => e.message?.toolName === "freeflow_unit")
235
- .at(-1).message.details;
236
- assert.equal(detail.supplement, "RECOVERY_SUPPLEMENT_73 [accepted]");
237
- assert.equal(detail.report, "BASE_REPORT_UNCHANGED_41");
238
- assert.equal(detail.reportRef, `report:${baseReportId}:${baseReportRevision}`);
239
- return [{ name: "freeflow_unit", args: { operation: "inspect", view: "detail", ref: recoveryRef } }];
240
- }
241
- const detail = manager
242
- .getBranch()
243
- .filter((e) => e.message?.toolName === "freeflow_unit")
244
- .at(-1).message.details;
245
- assert.equal(detail.recovery.state, "completed");
246
- assert.equal(detail.supplementRef, supplementRef);
247
- return [];
248
- },
249
- true,
250
- async ({ session, manager, requests }) => {
251
- await session.prompt("/freeflow resume");
252
- await session.waitForIdle();
253
- assert.equal(requests.length, 12);
254
- await session.compact();
255
- assert.equal(
256
- manager.buildSessionContext().messages.some((message) => message.role === "user"),
257
- false,
258
- );
259
- await session.reload();
260
- await session.prompt("/freeflow resume");
261
- await session.waitForIdle();
262
- await session.prompt("NEW_USER_ATTENTION_29");
263
- await session.waitForIdle();
264
- assert.equal(requests.length, 15);
265
- },
266
- true,
267
- { beforePrompt: (fixtureState) => (cwd = fixtureState.cwd), cognitiveRouting },
268
- );
269
- } finally {
270
- RoutingRuntime.prototype.invoke = originalInvoke;
271
- }
272
- },
273
- );
274
- }
275
-
276
- for (const returnedWorker of ["executor", "helper"]) {
277
- const cognitiveRouting =
278
- returnedWorker === "helper"
279
- ? {
280
- enabled: true,
281
- delegation: "helper",
282
- projection: true,
283
- profiles: {
284
- coordinator: { provider: "openai", model: "gpt-4o", thinking: "off" },
285
- helper: { provider: "openai", model: "gpt-4.1-mini", thinking: "off" },
286
- },
287
- }
288
- : undefined;
289
- test(`a blocked ${returnedWorker} return denies ordinary work before retry`, { timeout: 30000 }, async () => {
290
- let assignmentId;
291
- const result = await fixture(
292
- (n, body, manager) => {
293
- if (n === 1)
294
- return [
295
- { name: "freeflow_delegate", args: { operation: "assign", contract: "Return with a delivery gap." } },
296
- ];
297
- if (n === 2) {
298
- const state = replay(manager.getBranch());
299
- assignmentId = state.assignmentId;
300
- assert.equal(state.profile, returnedWorker);
301
- return [
302
- { name: "freeflow_project", args: { operation: "add", refs: ["ctx:missing"] } },
303
- {
304
- name: "freeflow_return",
305
- args: { operation: "submit", report: "RETURNED_WORKER_REPORT_67", outcome: "completed" },
306
- },
307
- ];
308
- }
309
- if (n === 3) {
310
- const state = replay(manager.getBranch());
311
- assert.equal(state.profile, returnedWorker);
312
- assert.equal(state.assignments.get(assignmentId).state, "returned");
313
- assert.equal(state.handoffs.get(state.assignments.get(assignmentId).returnHandoffId).state, "blocked");
314
- return [{ name: "read", args: { path: "evidence.txt" } }];
315
- }
316
- if (n === 4) {
317
- const denied = manager
318
- .getBranch()
319
- .filter((entry) => entry.message?.toolName === "read")
320
- .at(-1);
321
- assert.equal(denied.message.isError, true);
322
- assert.equal(denied.message.content[0].text, "worker_task_phase_ended");
323
- return [
324
- {
325
- name: "freeflow_project",
326
- args: { operation: "remove", refs: ["ctx:missing"], reason: "Resolve the fixture delivery gap." },
327
- },
328
- { name: "freeflow_return", args: { operation: "retry" } },
329
- ];
330
- }
331
- assert.equal(body.model, "gpt-4o");
332
- const state = replay(manager.getBranch());
333
- assert.equal(state.assignmentId, assignmentId);
334
- assert.equal(state.assignments.get(assignmentId).state, "returned");
335
- assert.equal(state.handoffs.get(state.assignments.get(assignmentId).returnHandoffId).state, "configured");
336
- assert.match(JSON.stringify(body), /RETURNED_WORKER_REPORT_67/);
337
- return [];
338
- },
339
- true,
340
- undefined,
341
- true,
342
- { cognitiveRouting, maxRequests: 7 },
343
- );
344
- assert.equal(result.requests.length, 5);
345
- });
346
- }
347
-
348
- test(
349
- "partial recovery supplement delivers communication while evidence remains suspended",
350
- { timeout: 30000 },
351
- async () => {
352
- let baseReportId;
353
- await fixture((n, body, manager) => {
354
- if (n === 1)
355
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return a base report." } }];
356
- if (n === 2)
357
- return [
358
- {
359
- name: "freeflow_return",
360
- args: { operation: "submit", report: "FALLBACK_BASE_REPORT_19", outcome: "completed" },
361
- },
362
- ];
363
- if (n === 3) {
364
- const state = replay(manager.getBranch());
365
- baseReportId = state.assignments.get(state.assignmentId).returnHandoffId;
366
- return [
367
- {
368
- name: "freeflow_unit",
369
- args: { operation: "recover", request: "Report unavailable evidence honestly." },
370
- },
371
- ];
372
- }
373
- if (n === 4)
374
- return [
375
- { name: "freeflow_project", args: { operation: "add", refs: ["ctx:missing"] } },
376
- {
377
- name: "freeflow_return",
378
- args: { operation: "supplement", report: "FALLBACK_SUPPLEMENT_23", outcome: "partial" },
379
- },
380
- ];
381
- assert.equal(body.model, "gpt-4o");
382
- const wire = JSON.stringify(body);
383
- assert.match(wire, /FALLBACK_BASE_REPORT_19/);
384
- assert.match(wire, /FALLBACK_SUPPLEMENT_23/);
385
- assert.match(wire, /source_unavailable|Exact source is unavailable/);
386
- const state = replay(manager.getBranch());
387
- assert.equal(state.assessment.handoffId, baseReportId);
388
- assert.equal(state.assessment.view, "suspended");
389
- assert.equal(state.assessment.suspensionReason, "delivery-gap");
390
- assert.equal(state.recoveryId, undefined);
391
- assert.equal([...state.recoveries.values()].at(-1).state, "completed");
392
- return [];
393
- });
394
- },
395
- );
396
-
397
- test(
398
- "recovery cancellation preserves the report and restores the same assessment explicitly",
399
- { timeout: 30000 },
400
- async () => {
401
- let baseReportId;
402
- await fixture(
403
- (n, _body, manager) => {
404
- if (n === 1)
405
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return a base report." } }];
406
- if (n === 2)
407
- return [
408
- { name: "freeflow_return", args: { operation: "submit", report: "CANCEL_BASE_31", outcome: "completed" } },
409
- ];
410
- if (n === 3) {
411
- const state = replay(manager.getBranch());
412
- baseReportId = state.assignments.get(state.assignmentId).returnHandoffId;
413
- return [{ name: "freeflow_unit", args: { operation: "recover", request: "Wait for cancellation." } }];
414
- }
415
- if (n === 4) return [];
416
- if (n === 5)
417
- return [{ name: "freeflow_unit", args: { operation: "cancel-recovery", reason: "No longer needed." } }];
418
- if (n === 6) {
419
- const state = replay(manager.getBranch());
420
- assert.equal(state.recoveryId, undefined);
421
- assert.equal([...state.recoveries.values()].at(-1).state, "cancelled");
422
- assert.equal(state.handoffs.get(baseReportId).text, "CANCEL_BASE_31");
423
- assert.equal(state.assessment.handoffId, baseReportId);
424
- assert.equal(state.assessment.view, "suspended");
425
- return [{ name: "freeflow_unit", args: { operation: "assess" } }];
426
- }
427
- assert.equal(replay(manager.getBranch()).assessment.view, "active");
428
- return [];
429
- },
430
- true,
431
- async ({ session }) => {
432
- await session.prompt("Cancel the evidence recovery without changing the report.");
433
- await session.waitForIdle();
434
- },
435
- );
436
- },
437
- );
438
-
439
- test(
440
- "fresh user recovery uses its own input basis without a changed-direction warning",
441
- { timeout: 30000 },
442
- async () => {
443
- await fixture(
444
- (n, body) => {
445
- if (n === 1) return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return once." } }];
446
- if (n === 2)
447
- return [{ name: "freeflow_return", args: { operation: "submit", report: "base", outcome: "completed" } }];
448
- if (n === 3) return [];
449
- if (n === 4)
450
- return [
451
- {
452
- name: "freeflow_unit",
453
- args: { operation: "recover", request: "Recover evidence for this assessment." },
454
- },
455
- ];
456
- if (n === 5) {
457
- const wire = JSON.stringify(body);
458
- assert.equal(body.model, "gpt-4.1-mini");
459
- assert.match(wire, /Recovery request: Recover evidence for this assessment\./);
460
- assert.doesNotMatch(wire, /Current input differs from the active Executor responsibility/);
461
- return [
462
- {
463
- name: "freeflow_return",
464
- args: { operation: "supplement", report: "fresh-basis supplement", outcome: "completed" },
465
- },
466
- ];
467
- }
468
- return [];
469
- },
470
- true,
471
- async ({ session }) => {
472
- await session.prompt("Please recover omitted evidence now.");
473
- await session.waitForIdle();
474
- },
475
- );
476
- },
477
- );
478
-
479
- test("assessment waits for recovery cancellation before resuming", { timeout: 30000 }, async () => {
480
- let selection;
481
- await fixture(
482
- (n, body, manager) => {
483
- if (n === 1) return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return once." } }];
484
- if (n === 2)
485
- return [{ name: "freeflow_return", args: { operation: "submit", report: "base", outcome: "completed" } }];
486
- if (n === 3) return [{ name: "freeflow_unit", args: { operation: "recover", request: "Recover later." } }];
487
- if (n === 4) {
488
- const state = replay(manager.getBranch());
489
- selection = structuredClone(state.selections.get(state.assignmentId));
490
- return [];
491
- }
492
- if (n === 5) {
493
- const wire = JSON.stringify(body);
494
- assert.match(
495
- wire,
496
- /Finish and deliver the recovery supplement or cancel recovery before using freeflow_unit assess/,
497
- );
498
- assert.doesNotMatch(wire, /Use freeflow_unit assess to restore the assessment/);
499
- return [{ name: "freeflow_unit", args: { operation: "assess" } }];
500
- }
501
- if (n === 6) {
502
- const state = replay(manager.getBranch());
503
- const result = manager
504
- .getBranch()
505
- .filter((entry) => entry.message?.toolName === "freeflow_unit")
506
- .at(-1).message;
507
- assert.equal(result.details.code, "recovery_outstanding");
508
- assert.equal(state.assessment.view, "suspended");
509
- assert.equal(state.assessment.suspensionReason, "user-attention");
510
- assert.equal(state.recoveries.get(state.recoveryId).state, "reading");
511
- assert.deepEqual(state.selections.get(state.assignmentId), selection);
512
- return [{ name: "freeflow_unit", args: { operation: "cancel-recovery", reason: "No longer needed." } }];
513
- }
514
- if (n === 7) {
515
- const state = replay(manager.getBranch());
516
- const wire = JSON.stringify(body);
517
- assert.equal(state.recoveryId, undefined);
518
- assert.equal(state.assessment.view, "suspended");
519
- assert.match(wire, /Use freeflow_unit assess to restore the assessment/);
520
- assert.doesNotMatch(
521
- JSON.stringify(
522
- body.input.filter((item) => JSON.stringify(item).includes("# Cognitive Routing Runtime State")).at(-1),
523
- ),
524
- /Finish and deliver the recovery supplement or cancel recovery/,
525
- );
526
- return [{ name: "freeflow_unit", args: { operation: "assess" } }];
527
- }
528
- const state = replay(manager.getBranch());
529
- assert.equal(state.assessment.view, "active");
530
- assert.equal(state.recoveryId, undefined);
531
- return [];
532
- },
533
- true,
534
- async ({ session }) => {
535
- await session.prompt("Assess before the open recovery is settled.");
536
- await session.waitForIdle();
537
- },
538
- );
539
- });
540
-
541
- test("cancelled unit closure atomically abandons attached recovery", { timeout: 30000 }, async () => {
542
- let baseReportId, selectionSnapshot;
543
- await fixture(
544
- (n, _body, manager) => {
545
- if (n === 1) return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return once." } }];
546
- if (n === 2)
547
- return [{ name: "freeflow_return", args: { operation: "submit", report: "close-base", outcome: "completed" } }];
548
- if (n === 3) {
549
- const state = replay(manager.getBranch());
550
- baseReportId = state.assignments.get(state.assignmentId).returnHandoffId;
551
- return [{ name: "freeflow_unit", args: { operation: "recover", request: "Recover later." } }];
552
- }
553
- if (n === 4) return [];
554
- if (n === 5) {
555
- selectionSnapshot = structuredClone([...replay(manager.getBranch()).selections]);
556
- return [
557
- {
558
- name: "freeflow_unit",
559
- args: { operation: "close", outcome: "cancelled", assessment: "Stop unit and recovery." },
560
- },
561
- ];
562
- }
563
- const state = replay(manager.getBranch());
564
- const recovery = [...state.recoveries.values()].at(-1);
565
- assert.equal(state.unitId, undefined);
566
- assert.equal(state.assignmentId, undefined);
567
- assert.equal(state.pendingId, undefined);
568
- assert.equal(state.recoveryId, undefined);
569
- assert.equal(recovery.state, "cancelled");
570
- assert.equal(recovery.cancellationReason, "Stop unit and recovery.");
571
- assert.equal(state.handoffs.get(baseReportId).text, "close-base");
572
- assert.deepEqual([...state.selections], selectionSnapshot);
573
- return [];
574
- },
575
- true,
576
- async ({ session }) => {
577
- await session.prompt("Cancel the unit and its recovery.");
578
- await session.waitForIdle();
579
- },
580
- );
581
- });
582
-
583
- test("projection-off recovery can read packaged instructions and resume assessment", { timeout: 30000 }, async () => {
584
- const packageRoot = process.cwd();
585
- await fixture(
586
- (n, body, manager) => {
587
- if (n === 1)
588
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return a base report." } }];
589
- if (n === 2)
590
- return [
591
- {
592
- name: "freeflow_return",
593
- args: { operation: "submit", report: "NO_PROJECTION_BASE_43", outcome: "completed" },
594
- },
595
- ];
596
- if (n === 3)
597
- return [
598
- { name: "freeflow_unit", args: { operation: "recover", request: "Read the packaged Workflow method." } },
599
- ];
600
- if (n === 4)
601
- return [{ name: "read", args: { path: join(packageRoot, "skills/workflow/SKILL.md"), offset: 1, limit: 8 } }];
602
- if (n === 5) {
603
- const read = manager
604
- .getBranch()
605
- .filter((e) => e.message?.toolName === "read")
606
- .at(-1);
607
- assert.equal(read.message.isError, false);
608
- assert.match(JSON.stringify(read.message), /name: workflow|# Workflow/);
609
- return [
610
- {
611
- name: "freeflow_return",
612
- args: { operation: "supplement", report: "PACKAGED_METHOD_READ_47", outcome: "completed" },
613
- },
614
- ];
615
- }
616
- assert.equal(body.model, "gpt-4o");
617
- const state = replay(manager.getBranch());
618
- assert.equal(state.assessment.view, "active");
619
- assert.equal(state.recoveryId, undefined);
620
- assert.match(JSON.stringify(body), /NO_PROJECTION_BASE_43/);
621
- assert.match(JSON.stringify(body), /PACKAGED_METHOD_READ_47/);
622
- return [];
623
- },
624
- false,
625
- undefined,
626
- true,
627
- );
628
- });
629
-
630
- test(
631
- "new input during recovery blocks further reads and a supplement preserves user attention",
632
- { timeout: 30000 },
633
- async () => {
634
- let active, assignmentId, baseReportId;
635
- await fixture(
636
- async (n, body, manager) => {
637
- if (n === 1)
638
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return a base report." } }];
639
- if (n === 2)
640
- return [
641
- {
642
- name: "freeflow_return",
643
- args: { operation: "submit", report: "INTERRUPTED_RECOVERY_BASE_59", outcome: "completed" },
644
- },
645
- ];
646
- if (n === 3) {
647
- const state = replay(manager.getBranch());
648
- assignmentId = state.assignmentId;
649
- baseReportId = state.assignments.get(assignmentId).returnHandoffId;
650
- return [
651
- {
652
- name: "freeflow_unit",
653
- args: { operation: "recover", request: "Read only recovery.txt.", paths: ["recovery.txt"] },
654
- },
655
- ];
656
- }
657
- if (n === 4) {
658
- assert.equal(body.model, "gpt-4.1-mini");
659
- await active.steer("NEW_RECOVERY_ATTENTION_61");
660
- return [{ name: "read", args: { path: "recovery.txt" } }];
661
- }
662
- if (n === 5) {
663
- const state = replay(manager.getBranch());
664
- assert.equal(state.assessment.view, "suspended");
665
- assert.equal(state.assessment.suspensionReason, "user-attention");
666
- assert.match(JSON.stringify(body), /New delivered user input requires Coordinator attention/);
667
- return [{ name: "read", args: { path: "recovery.txt" } }];
668
- }
669
- if (n === 6) {
670
- const lastRead = manager
671
- .getBranch()
672
- .filter((entry) => entry.message?.toolName === "read")
673
- .at(-1);
674
- assert.equal(lastRead.message.isError, true, "new input revokes recovery-read permission");
675
- return [
676
- {
677
- name: "freeflow_return",
678
- args: { operation: "supplement", report: "INTERRUPTED_RECOVERY_SUPPLEMENT_67", outcome: "partial" },
679
- },
680
- ];
681
- }
682
- assert.equal(body.model, "gpt-4o");
683
- assert.match(JSON.stringify(body), /NEW_RECOVERY_ATTENTION_61/);
684
- assert.match(JSON.stringify(body), /INTERRUPTED_RECOVERY_SUPPLEMENT_67/);
685
- const state = replay(manager.getBranch());
686
- assert.equal(state.assignmentId, assignmentId);
687
- assert.equal(state.assignments.get(assignmentId).state, "returned");
688
- assert.equal(state.assignments.get(assignmentId).returnHandoffId, baseReportId);
689
- assert.equal(state.handoffs.get(baseReportId).text, "INTERRUPTED_RECOVERY_BASE_59");
690
- assert.equal(state.assessment.handoffId, baseReportId);
691
- assert.equal(state.assessment.view, "suspended");
692
- assert.equal(state.assessment.suspensionReason, "user-attention");
693
- assert.equal(state.recoveryId, undefined);
694
- assert.equal([...state.recoveries.values()].at(-1).state, "completed");
695
- return [];
696
- },
697
- true,
698
- undefined,
699
- true,
700
- { onSession: (session) => (active = session) },
701
- );
702
- },
703
- );
704
-
705
- test("manual hold and navigation preserve an unchanged recovery for explicit resume", { timeout: 30000 }, async () => {
706
- let assignmentId, baseReportId, recoveryId, requestHandoffId;
707
- await fixture(
708
- (n, body, manager) => {
709
- if (n === 1)
710
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return a base report." } }];
711
- if (n === 2)
712
- return [
713
- {
714
- name: "freeflow_return",
715
- args: { operation: "submit", report: "MANUAL_RECOVERY_BASE_71", outcome: "completed" },
716
- },
717
- ];
718
- if (n === 3) {
719
- const state = replay(manager.getBranch());
720
- assignmentId = state.assignmentId;
721
- baseReportId = state.assignments.get(assignmentId).returnHandoffId;
722
- return [{ name: "freeflow_unit", args: { operation: "recover", request: "Resume this lookup unchanged." } }];
723
- }
724
- if (n === 4) {
725
- const state = replay(manager.getBranch());
726
- recoveryId = state.recoveryId;
727
- requestHandoffId = state.recoveries.get(recoveryId).requestHandoffId;
728
- assert.equal(state.recoveries.get(recoveryId).state, "reading");
729
- return [];
730
- }
731
- if (n === 5) {
732
- const state = replay(manager.getBranch());
733
- assert.equal(body.model, "gpt-4.1-mini");
734
- assert.equal(state.recoveryId, recoveryId);
735
- assert.equal(state.recoveries.get(recoveryId).state, "reading");
736
- assert.equal(state.assignmentId, assignmentId);
737
- assert.equal(state.assignments.get(assignmentId).state, "returned");
738
- return [
739
- {
740
- name: "freeflow_return",
741
- args: { operation: "supplement", report: "MANUAL_RECOVERY_SUPPLEMENT_73", outcome: "completed" },
742
- },
743
- ];
744
- }
745
- const state = replay(manager.getBranch());
746
- assert.equal(body.model, "gpt-4o");
747
- assert.equal(state.control, "automatic");
748
- assert.equal(state.assignmentId, assignmentId);
749
- assert.equal(state.assignments.get(assignmentId).returnHandoffId, baseReportId);
750
- assert.equal(state.handoffs.get(baseReportId).text, "MANUAL_RECOVERY_BASE_71");
751
- assert.equal(state.assessment.handoffId, baseReportId);
752
- assert.equal(state.assessment.view, "active");
753
- assert.equal(state.recoveries.get(recoveryId).state, "completed");
754
- assert.equal(state.recoveries.size, 1);
755
- assert.equal(state.assignments.size, 1);
756
- return [];
757
- },
758
- true,
759
- async ({ session, manager, requests }) => {
760
- const reads = manager.getEntries().filter((entry) => entry.message?.toolName === "read").length;
761
- await session.prompt("/freeflow profile executor");
762
- const configured = manager
763
- .getEntries()
764
- .find(
765
- (entry) =>
766
- entry.data?.data?.type === "handoff-state" &&
767
- entry.data.data.handoffId === requestHandoffId &&
768
- entry.data.data.state === "configured",
769
- );
770
- await session.navigateTree(configured.id, { summarize: false });
771
- const before = requests.length;
772
- await session.prompt("/freeflow resume");
773
- assert.equal(requests.length, before, "resume cannot release a manual hold");
774
- let state = replay(manager.getBranch());
775
- assert.equal(state.control, "manual");
776
- assert.equal(state.profile, "executor");
777
- assert.equal(state.recoveryId, recoveryId);
778
- assert.equal(state.recoveries.get(recoveryId).state, "reading");
779
- await session.prompt("/freeflow profile auto");
780
- state = replay(manager.getBranch());
781
- assert.equal(state.control, "automatic");
782
- assert.equal(state.profile, "coordinator");
783
- await session.prompt("/freeflow resume");
784
- await session.waitForIdle();
785
- assert.equal(requests.length, before + 2);
786
- assert.equal(
787
- manager.getEntries().filter((entry) => entry.message?.toolName === "read").length,
788
- reads,
789
- "navigation and resume do not replay task reads",
790
- );
791
- },
792
- );
793
- });
794
-
795
- test(
796
- "resume after attention restores saved-return correction without reopening task work",
797
- { timeout: 30000 },
798
- async () => {
799
- let reportId;
800
- await fixture(
801
- (n, body, manager) => {
802
- if (n === 1)
803
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Read and report." } }];
804
- if (n === 2) return [{ name: "read", args: { path: "evidence.txt" } }];
805
- if (n === 3)
806
- return [
807
- { name: "freeflow_project", args: { operation: "add", refs: ["ctx:missing"] } },
808
- {
809
- name: "freeflow_return",
810
- args: { operation: "submit", report: "ORIGINAL_SAVED_REPORT", outcome: "partial" },
811
- },
812
- ];
813
- if (n === 4) {
814
- reportId = replay(manager.getBranch()).pendingId;
815
- return [];
816
- }
817
- if (n === 5) {
818
- assert.equal(body.model, "gpt-4o");
819
- return [];
820
- }
821
- if (n === 6) {
822
- assert.equal(body.model, "gpt-4.1-mini");
823
- return [{ name: "read", args: { path: "unselected.txt" } }];
824
- }
825
- if (n === 7) {
826
- assert.equal(
827
- manager
828
- .getBranch()
829
- .filter((e) => e.message?.toolName === "read")
830
- .at(-1).message.isError,
831
- true,
832
- );
833
- return [
834
- {
835
- name: "freeflow_project",
836
- args: {
837
- operation: "remove",
838
- refs: ["ctx:missing"],
839
- reason: "Invalid reference; evidence gap remains disclosed.",
840
- },
841
- },
842
- { name: "freeflow_return", args: { operation: "retry" } },
843
- ];
844
- }
845
- assert.equal(body.model, "gpt-4o");
846
- assert.match(JSON.stringify(body), /ORIGINAL_SAVED_REPORT/);
847
- assert.match(JSON.stringify(body), /evidence gap remains disclosed/);
848
- const state = replay(manager.getBranch());
849
- assert.equal(state.assessment.handoffId, reportId);
850
- assert.equal(state.handoffs.get(reportId).reportRevision, 1);
851
- assert.equal(state.assessment.view, "active");
852
- return [];
853
- },
854
- true,
855
- async ({ session, requests }) => {
856
- await session.prompt("Explain the saved return's problem.");
857
- await session.waitForIdle();
858
- await session.prompt("/freeflow resume");
859
- await session.waitForIdle();
860
- assert.equal(requests.length, 8);
861
- },
862
- );
863
- },
864
- );
865
-
866
- const normal = (n) =>
867
- n === 1
868
- ? [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Read evidence.txt and report." } }]
869
- : n === 2
870
- ? [{ name: "read", args: { path: "evidence.txt" } }]
871
- : n === 3
872
- ? [{ name: "freeflow_return", args: { operation: "submit", report: "Read completed.", outcome: "completed" } }]
873
- : [];
874
-
875
- for (const cut of ["delegate-accepted", "executor-configured", "executor-call", "read-result", "return-accepted"]) {
876
- test(`native navigation reconciles valid ${cut} without replaying work`, { timeout: 30000 }, async () => {
877
- await fixture(normal, false, async ({ session, manager, requests }) => {
878
- const chosen = manager
879
- .getEntries()
880
- .find((e) =>
881
- cut === "executor-configured"
882
- ? e.data?.data?.type === "handoff-state" && e.data.data.state === "configured"
883
- : cut === "executor-call"
884
- ? e.message?.role === "assistant" && e.message.content?.some((b) => b.name === "read")
885
- : cut === "read-result"
886
- ? e.message?.toolName === "read"
887
- : e.data?.data?.type === cut,
888
- );
889
- const reads = manager.getEntries().filter((e) => e.message?.toolName === "read").length;
890
- await session.navigateTree(chosen.id, { summarize: false });
891
- const before = requests.length;
892
- await session.prompt("Explain the saved state at this point.");
893
- await session.waitForIdle();
894
- assert.equal(requests.length, before + 1);
895
- assert.equal(requests.at(-1).model, "gpt-4o");
896
- assert.equal(manager.getEntries().filter((e) => e.message?.toolName === "read").length, reads);
897
- assert.equal(replay(manager.getBranch()).profile, "coordinator");
898
- });
899
- });
900
- }
901
-
902
- test(
903
- "explicit resume continues the same assignment after Coordinator handles new input",
904
- { timeout: 30000 },
905
- async () => {
906
- let assignment, unit;
907
- await fixture(
908
- (n, body, manager) => {
909
- if (n <= 2) return normal(n);
910
- if (n === 3) {
911
- const s = replay(manager.getBranch());
912
- assignment = s.assignmentId;
913
- unit = s.unitId;
914
- return [];
915
- }
916
- if (n === 4) {
917
- assert.equal(body.model, "gpt-4o");
918
- return [];
919
- }
920
- if (n === 5) {
921
- assert.equal(body.model, "gpt-4.1-mini");
922
- const s = replay(manager.getBranch());
923
- assert.equal(s.assignmentId, assignment);
924
- assert.equal(s.unitId, unit);
925
- assert.equal(s.assignments.size, 1);
926
- assert.match(JSON.stringify(body), /Do not edit files/);
927
- assert.doesNotMatch(JSON.stringify(body), /New delivered user input requires Coordinator attention/);
928
- return [{ name: "read", args: { path: "unselected.txt" } }];
929
- }
930
- if (n === 6) {
931
- const read = manager
932
- .getBranch()
933
- .filter((e) => e.message?.toolName === "read")
934
- .at(-1);
935
- assert.equal(read.message.isError, false);
936
- return [
937
- {
938
- name: "freeflow_return",
939
- args: { operation: "submit", report: "Resumed read completed; no edits.", outcome: "completed" },
940
- },
941
- ];
942
- }
943
- assert.equal(body.model, "gpt-4o");
944
- return [];
945
- },
946
- false,
947
- async ({ session, manager, requests }) => {
948
- await session.prompt("Do not edit files. Explain the current partial result.");
949
- await session.waitForIdle();
950
- await session.prompt("/freeflow resume");
951
- await session.waitForIdle();
952
- assert.equal(requests.length, 7);
953
- assert.equal(replay(manager.getBranch()).assignments.get(assignment).state, "returned");
954
- },
955
- );
956
- },
957
- );
958
-
959
- test("current manual hold survives navigation and resume cannot release it", { timeout: 30000 }, async () => {
960
- await fixture(normal, false, async ({ session, manager, requests }) => {
961
- const old = manager.getEntries().find((e) => e.data?.data?.type === "delegate-accepted");
962
- await session.prompt("/freeflow profile executor");
963
- await session.navigateTree(old.id, { summarize: false });
964
- const before = requests.length;
965
- await session.prompt("/freeflow resume");
966
- assert.equal(requests.length, before);
967
- const s = replay(manager.getBranch());
968
- assert.equal(s.control, "manual");
969
- assert.equal(s.profile, "executor");
970
- assert.equal(session.model.id, "gpt-4.1-mini");
971
- });
972
- });
973
-
974
- test(
975
- "late steering keeps the captured Executor request coherent and blocks dependent task tools",
976
- { timeout: 30000 },
977
- async () => {
978
- let active;
979
- await fixture(
980
- async (n, body, manager) => {
981
- if (n === 1) return normal(n);
982
- if (n === 2) {
983
- await active.steer("Stop further reads and explain the current result.");
984
- return normal(n);
985
- }
986
- if (n === 3) {
987
- assert.equal(body.model, "gpt-4.1-mini");
988
- assert.match(JSON.stringify(body), /New delivered user input requires Coordinator attention/);
989
- assert.ok(
990
- body.tools.some((t) => t.name === "freeflow_delegate"),
991
- "stable catalog retains definitions; runtime gates still deny wrong-role effects",
992
- );
993
- assert.deepEqual(body.tools.find((t) => t.name === "freeflow_unit").parameters.properties.operation.enum, [
994
- "inspect",
995
- "assess",
996
- "recover",
997
- "cancel-recovery",
998
- "close",
999
- ]);
1000
- return [{ name: "read", args: { path: "unselected.txt" } }];
1001
- }
1002
- if (n === 4) {
1003
- assert.equal(
1004
- manager
1005
- .getBranch()
1006
- .filter((e) => e.message?.toolName === "read")
1007
- .at(-1).message.isError,
1008
- true,
1009
- );
1010
- return [
1011
- {
1012
- name: "freeflow_return",
1013
- args: { operation: "submit", report: "Stopped for the newer instruction.", outcome: "partial" },
1014
- },
1015
- ];
1016
- }
1017
- assert.equal(body.model, "gpt-4o");
1018
- assert.ok(
1019
- body.tools.some((t) => t.name === "freeflow_return") && body.tools.some((t) => t.name === "freeflow_project"),
1020
- );
1021
- assert.match(JSON.stringify(body), /Stop further reads/);
1022
- return [];
1023
- },
1024
- false,
1025
- undefined,
1026
- true,
1027
- {
1028
- onSession: (session) => {
1029
- active = session;
1030
- },
1031
- },
1032
- );
1033
- },
1034
- );