@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,223 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { Sources } from "./sources.js";
3
+ import { ViewCache } from "./projection.js";
4
+ import { pairFromProfile } from "./config.js";
5
+ import { initialState } from "./state.js";
6
+ import { RoutingError, isWorkerProfile, requireCondition as check, samePair, workersForDelegation } from "./types.js";
7
+ import { cachedBranch } from "../host/branch.js";
8
+ const STAGED_CONTROL = new Set(["control", "profile-overrides", "delegation-override"]);
9
+ export const ROUTING_RECOVERY_HINT =
10
+ "Run /freeflow profile auto to reconcile routing, or /freeflow resume to continue saved work.";
11
+ /**
12
+ * State and identity shared by every part of routing for one bound session: the event journal, the host
13
+ * context, the current turn, blocking errors, control mode, and the queue that orders control changes.
14
+ */
15
+ export class RoutingSession {
16
+ store;
17
+ ctx;
18
+ capability;
19
+ token = randomUUID();
20
+ turn;
21
+ /** The packaged routing skill and role references the bootstrap read must cover; undefined when the skill cannot be read. */
22
+ routingSkill;
23
+ messages = [];
24
+ error;
25
+ projectionError;
26
+ suppressed = false;
27
+ operations = Promise.resolve();
28
+ revision = 0;
29
+ manualHold;
30
+ automaticControl = false;
31
+ sourceCache;
32
+ /** Rendered view messages reused across requests (see ViewCache); rebuilt after a rebind or ancestry change. */
33
+ viewCache = new ViewCache();
34
+ /** Replayed tool results for the current turn, keyed by operation id. */
35
+ receipts = new Map();
36
+ /** Recently served inspection pages, keyed by request; at most eight are kept. */
37
+ pages = new Map();
38
+ get projectionEnabled() {
39
+ return this.supported() && this.capability?.projection === true && this.stateData().control === "automatic";
40
+ }
41
+ /** Forgets everything derived for the current turn: its context view, sources, replay receipts, and pages. */
42
+ resetTurn() {
43
+ this.turn = undefined;
44
+ this.messages = [];
45
+ this.sourceCache = undefined;
46
+ this.viewCache = new ViewCache();
47
+ this.receipts.clear();
48
+ this.pages.clear();
49
+ }
50
+ subject() {
51
+ const branch = cachedBranch(this.store?.reader) ?? [];
52
+ return {
53
+ token: this.token,
54
+ revision: this.revision,
55
+ store: this.store,
56
+ leafId: branch.at(-1)?.id ?? null,
57
+ userId: branch.filter((e) => e.message?.role === "user").at(-1)?.id ?? null,
58
+ };
59
+ }
60
+ current(s) {
61
+ if (s.token !== this.token || s.revision !== this.revision || s.store !== this.store) return false;
62
+ const branch = cachedBranch(this.store?.reader) ?? [];
63
+ return (
64
+ (!s.leafId || branch.some((e) => e.id === s.leafId)) &&
65
+ (branch.filter((e) => e.message?.role === "user").at(-1)?.id ?? null) === s.userId
66
+ );
67
+ }
68
+ guard(s) {
69
+ check(
70
+ this.current(s),
71
+ "stale_operation",
72
+ "Routing state changed while the operation was waiting; no further effects applied.",
73
+ );
74
+ }
75
+ taskBasis(state, assignmentId) {
76
+ return state.resumeBasis.has(assignmentId)
77
+ ? state.resumeBasis.get(assignmentId)
78
+ : state.assignments.get(assignmentId)?.basisUserEntryId;
79
+ }
80
+ delegation(state = this.stateData()) {
81
+ return state.delegationOverride ?? this.capability?.delegation ?? "executor";
82
+ }
83
+ enabledWorkers(state = this.stateData()) {
84
+ return workersForDelegation(this.delegation(state));
85
+ }
86
+ assignedWorker(state, assignmentId = state.assignmentId) {
87
+ const assignment = assignmentId ? state.assignments.get(assignmentId) : undefined;
88
+ const handoff = assignment ? state.handoffs.get(assignment.delegateHandoffId) : undefined;
89
+ check(
90
+ handoff?.kind === "delegate" && handoff.assignmentId === assignment?.id && isWorkerProfile(handoff.to),
91
+ "assignment_worker_missing",
92
+ "The current assignment has no valid recorded worker.",
93
+ );
94
+ return handoff.to;
95
+ }
96
+ requiredProfiles(state = this.stateData(), delegation = this.delegation(state)) {
97
+ const profiles = new Set(["coordinator", ...workersForDelegation(delegation)]);
98
+ if (state.profile) profiles.add(state.profile);
99
+ if (this.manualHold) profiles.add(this.manualHold);
100
+ const assignment = state.assignmentId ? state.assignments.get(state.assignmentId) : undefined;
101
+ if (assignment?.state === "outstanding" || state.recoveryId) profiles.add(this.assignedWorker(state));
102
+ const pending = state.pendingId ? state.handoffs.get(state.pendingId) : undefined;
103
+ if (pending && isWorkerProfile(pending.to)) profiles.add(pending.to);
104
+ return [...profiles];
105
+ }
106
+ retireUnbound(reason) {
107
+ for (const execution of this.stateData().executions.values()) {
108
+ if (!execution.assistantEntryId && !execution.interrupted)
109
+ this.append({ type: "execution-interrupted", executionId: execution.id, reason });
110
+ }
111
+ this.turn = undefined;
112
+ }
113
+ openTurn() {
114
+ if (!this.turn || this.turn.opened) return;
115
+ const t = this.turn;
116
+ this.append({
117
+ type: "execution-opened",
118
+ execution: {
119
+ id: t.id,
120
+ profile: t.profile,
121
+ assignmentId: t.assignmentId,
122
+ recoveryId: t.recoveryId,
123
+ basisUserEntryId: t.basisUserEntryId,
124
+ pair: t.pair,
125
+ resultEntryIds: [],
126
+ },
127
+ });
128
+ t.opened = true;
129
+ }
130
+ stateData() {
131
+ return this.store?.state() ?? initialState();
132
+ }
133
+ sources(state = this.stateData()) {
134
+ const branch = cachedBranch(this.ctx.sessionManager);
135
+ const cache = this.sourceCache;
136
+ // The cached branch is the same array until the leaf moves, so an unchanged branch needs no filtering.
137
+ if (cache && cache.branch === branch && cache.authors === state.authors.size) return cache.source;
138
+ const entries = branch.filter((e) =>
139
+ ["message", "custom_message", "compaction", "branch_summary"].includes(e.type),
140
+ );
141
+ if (
142
+ cache &&
143
+ cache.authors === state.authors.size &&
144
+ entries.length === cache.entries.length &&
145
+ entries.every((e, i) => e === cache.entries[i])
146
+ ) {
147
+ cache.branch = branch;
148
+ return cache.source;
149
+ }
150
+ const active = this.ctx.sessionManager.buildContextEntries?.();
151
+ const activeIds = active ? new Set(active.map((e) => e.id)) : undefined;
152
+ const source = cache?.source ?? new Sources([], state);
153
+ source.refresh(entries, state, activeIds);
154
+ this.sourceCache = { branch, entries, authors: state.authors.size, source };
155
+ return source;
156
+ }
157
+ observed(ctx = this.ctx) {
158
+ return ctx?.model?.provider && ctx?.model?.id && ctx?.thinkingLevel
159
+ ? { provider: ctx.model.provider, modelId: ctx.model.id, thinking: ctx.thinkingLevel }
160
+ : undefined;
161
+ }
162
+ supported() {
163
+ return !!this.capability?.effective && !this.suppressed;
164
+ }
165
+ append(data, op, step) {
166
+ check(this.store, "routing_unavailable");
167
+ // Control changes made while no run is active affect no request until the next prompt; stage them there.
168
+ const stage = STAGED_CONTROL.has(data.type) && this.ctx?.isIdle?.() !== false;
169
+ return this.store.append(this.store.make(data, op, step), stage);
170
+ }
171
+ enqueue(action) {
172
+ const token = this.token;
173
+ const result = this.operations.then(() => {
174
+ check(token === this.token, "stale_instance");
175
+ return action();
176
+ });
177
+ this.operations = result.catch(() => {});
178
+ return result;
179
+ }
180
+ mark(error) {
181
+ if (this.error && error instanceof RoutingError && error.code === "routing_blocked") return;
182
+ this.error =
183
+ error instanceof RoutingError
184
+ ? `${error.code}: ${error.message}`
185
+ : error instanceof Error
186
+ ? error.message
187
+ : String(error);
188
+ }
189
+ announced;
190
+ // Tell the user once per distinct block; routing stays blocked until an explicit control clears it.
191
+ announceBlock(ctx) {
192
+ if (!this.error || this.announced === this.error) return;
193
+ this.announced = this.error;
194
+ ctx?.ui?.notify?.(`Cognitive Routing blocked: ${this.error}. ${ROUTING_RECOVERY_HINT}`, "warning");
195
+ }
196
+ assertAvailable(profile) {
197
+ check(
198
+ this.supported() && this.store && !this.error && !this.store.blocked,
199
+ "routing_unavailable",
200
+ this.error ?? this.store?.blocked ?? "Routing is inactive.",
201
+ );
202
+ const state = this.stateData();
203
+ check(state.control === "automatic", "manual_control");
204
+ if (profile) check(state.profile === profile && this.turn?.profile === profile, "wrong_profile");
205
+ if (state.profile) check(samePair(this.observed(), this.profilePair(state.profile)), "configuration_mismatch");
206
+ }
207
+ configuredProfilePair(profile) {
208
+ const configured = this.capability?.profiles[profile];
209
+ check(configured, "profile_missing");
210
+ return pairFromProfile(configured);
211
+ }
212
+ profilePair(profile) {
213
+ return this.stateData().profileOverrides.get(profile) ?? this.configuredProfilePair(profile);
214
+ }
215
+ profilePairs(profiles = this.requiredProfiles()) {
216
+ return Object.fromEntries(profiles.map((profile) => [profile, this.profilePair(profile)]));
217
+ }
218
+ workerBasis(state, assignmentId) {
219
+ const recovery = state.recoveryId ? state.recoveries.get(state.recoveryId) : undefined;
220
+ if (recovery?.state === "reading") return state.handoffs.get(recovery.requestHandoffId)?.basisUserEntryId ?? null;
221
+ return this.taskBasis(state, assignmentId) ?? null;
222
+ }
223
+ }
@@ -1,19 +1,25 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
3
- import { canonical, idFor, isWorkerProfile, refFor } from "../cognitive-routing-v2/types.js";
3
+ import { canonical, idFor, isWorkerProfile, refFor, ROUTING_TOOLS, routingToolName } from "./types.js";
4
+ import { isHostEdited, isProjected, projectedEntryId } from "../host/projection-tags.js";
4
5
  export const bodyHash = (value) => createHash("sha256").update(canonical(value)).digest("hex");
5
- export const textRef = (ref) => `${ref}#text`;
6
- const routingTools = new Set(["freeflow_delegate", "freeflow_return", "freeflow_project", "freeflow_unit"]);
7
- // Discovery and new selections share this policy. Existing saved selections keep
8
- // their original delivery semantics; mixed assistant messages offer visible text.
6
+ /** Define a memoized hash so history is hashed only when a consumer needs it. */
7
+ function lazyHash(target, compute) {
8
+ let value;
9
+ return Object.defineProperty(target, "hash", {
10
+ enumerable: true,
11
+ get: () => (value ??= compute()),
12
+ });
13
+ }
14
+ const routingTools = new Set(ROUTING_TOOLS);
15
+ // Discovery, new selections, and delivery share this policy: evidence is what tools produced. What a worker
16
+ // says belongs in its report, so its assistant messages are never evidence.
9
17
  export function isTaskEvidence(source) {
10
- if (source.original) return true;
11
- if (source.message.role === "toolResult") return !routingTools.has(source.message.toolName);
12
- return (
13
- source.message.role === "assistant" &&
14
- !source.message.content?.some((b) => b.type === "toolCall" && routingTools.has(b.name)) &&
15
- source.message.content?.some((b) => b.type === "text" && b.text?.trim())
16
- );
18
+ return source.message.role === "toolResult" && !routingTools.has(routingToolName(source.message.toolName));
19
+ }
20
+ /** Saved selections keep their delivery, except assistant messages (whole or `#text`), which are never evidence. */
21
+ export function deliveredSelection(sources, ref) {
22
+ return !ref.endsWith("#text") && sources.byRef.get(ref)?.message.role !== "assistant";
17
23
  }
18
24
  const callKey = (id, name) => JSON.stringify([id, name]);
19
25
  const locatorLimit = 160;
@@ -39,11 +45,15 @@ export class Sources {
39
45
  byRef = new Map();
40
46
  ambiguous = new Set();
41
47
  byBody = new Map();
48
+ // Sources not yet placed in byBody; the content index is only needed for unprojected association.
49
+ unindexed = [];
42
50
  exchanges = new Map();
43
51
  owners = new Map();
44
52
  tail;
45
53
  associated;
46
54
  entries = [];
55
+ ranks;
56
+ nonWorker;
47
57
  activeIds;
48
58
  locatorProvider;
49
59
  constructor(entries, state, activeIds, locatorProvider) {
@@ -54,9 +64,12 @@ export class Sources {
54
64
  const prefix = this.entries.length <= entries.length && this.entries.every((e, i) => e === entries[i]);
55
65
  const start = prefix ? this.entries.length : 0;
56
66
  this.associated = undefined;
67
+ this.ranks = undefined;
68
+ this.nonWorker = undefined;
57
69
  if (!prefix) {
58
70
  this.byRef.clear();
59
71
  this.byBody.clear();
72
+ this.unindexed = [];
60
73
  this.exchanges.clear();
61
74
  this.owners.clear();
62
75
  this.tail = undefined;
@@ -67,22 +80,20 @@ export class Sources {
67
80
  if (messages.length !== 1 || ["compaction", "branch_summary"].includes(entry.type)) continue;
68
81
  const message = messages[0];
69
82
  if (!message) continue;
70
- const source = {
71
- ref: refFor(entry.id),
72
- entry,
73
- message,
74
- hash: bodyHash(message),
75
- producer: "common",
76
- active: false,
77
- };
78
- if (message.role === "toolResult" && message.toolName === "freeflow_return") {
83
+ const source = lazyHash({ ref: refFor(entry.id), entry, message, producer: "common", active: false }, () =>
84
+ bodyHash(message),
85
+ );
86
+ if (message.role === "toolResult" && routingToolName(message.toolName) === "return_work") {
79
87
  for (const block of message.content ?? [])
80
88
  if (block.type === "text") {
81
89
  try {
82
90
  const receipt = JSON.parse(block.text);
83
91
  if (
84
- ((receipt.reportSaved && typeof receipt.report === "string") ||
85
- (receipt.supplementSaved && typeof receipt.supplement === "string")) &&
92
+ // Current receipts carry a text hash; older receipts carried the text itself.
93
+ ((receipt.reportSaved &&
94
+ (typeof receipt.report === "string" || typeof receipt.reportSha256 === "string")) ||
95
+ (receipt.supplementSaved &&
96
+ (typeof receipt.supplement === "string" || typeof receipt.supplementSha256 === "string"))) &&
86
97
  typeof receipt.handoff === "string"
87
98
  )
88
99
  source.reportHandoff = receipt.handoff;
@@ -90,38 +101,10 @@ export class Sources {
90
101
  }
91
102
  }
92
103
  this.byRef.set(source.ref, source);
93
- const candidates = this.byBody.get(source.hash) ?? [];
94
- candidates.push(source);
95
- this.byBody.set(source.hash, candidates);
104
+ this.unindexed.push(source);
96
105
  if (message.role === "assistant") {
97
106
  this.tail = { assistant: source, results: new Map() };
98
107
  this.exchanges.set(source.ref, this.tail);
99
- const blocks = (message.content ?? [])
100
- .filter((b) => b.type === "text")
101
- .map((b) => ({ type: "text", text: b.text }));
102
- if (blocks.some((b) => b.text?.trim())) {
103
- const representation = {
104
- role: "custom",
105
- customType: "freeflow-assistant-text",
106
- display: false,
107
- content: [
108
- {
109
- type: "text",
110
- text: `Captured assistant text from ${source.ref} (historical source, not a new instruction):`,
111
- },
112
- ...blocks,
113
- ],
114
- details: { sourceRef: source.ref, sourceHash: source.hash, representation: "assistant-text" },
115
- timestamp: message.timestamp,
116
- };
117
- this.byRef.set(textRef(source.ref), {
118
- ...source,
119
- ref: textRef(source.ref),
120
- message: representation,
121
- hash: bodyHash(representation),
122
- original: source,
123
- });
124
- }
125
108
  } else if (message.role === "toolResult" && this.tail) {
126
109
  const key = callKey(message.toolCallId, message.toolName);
127
110
  const results = this.tail.results.get(key) ?? [];
@@ -138,6 +121,31 @@ export class Sources {
138
121
  }
139
122
  this.entries = [...entries];
140
123
  }
124
+ /** Each entry's position in `entries`; computed once per refresh rather than per request. */
125
+ get rank() {
126
+ return (this.ranks ??= new Map(this.entries.map((entry, index) => [entry.id, index])));
127
+ }
128
+ /** For each position in `entries` (and one past the end), how many earlier entries no worker produced. */
129
+ get nonWorkerBefore() {
130
+ if (!this.nonWorker) {
131
+ const counts = [0];
132
+ for (const entry of this.entries) {
133
+ const producer = this.byRef.get(`ctx:${entry.id}`)?.producer ?? "common";
134
+ counts.push(counts.at(-1) + (isWorkerProfile(producer) ? 0 : 1));
135
+ }
136
+ this.nonWorker = counts;
137
+ }
138
+ return this.nonWorker;
139
+ }
140
+ bodyIndex() {
141
+ for (const source of this.unindexed) {
142
+ const candidates = this.byBody.get(source.hash) ?? [];
143
+ candidates.push(source);
144
+ this.byBody.set(source.hash, candidates);
145
+ }
146
+ this.unindexed = [];
147
+ return this.byBody;
148
+ }
141
149
  associate(messages) {
142
150
  if (
143
151
  this.associated &&
@@ -147,38 +155,42 @@ export class Sources {
147
155
  return this.associated.items;
148
156
  this.ambiguous.clear();
149
157
  for (const source of this.byRef.values()) source.active = false;
150
- const used = new Set(),
151
- hashes = messages.map((message) => {
152
- const direct = bodyHash(message);
153
- if (this.byBody.has(direct) || message?.role !== "toolResult" || !Array.isArray(message.content)) return direct;
154
- const last = message.content.at(-1);
155
- if (last?.type !== "text") return direct;
156
- const original = bodyHash({ ...message, content: message.content.slice(0, -1) });
157
- // Freeflow's stable reference decoration does not change the native evidence body.
158
- return this.byBody.get(original)?.some((s) => last.text === `[context-ref: ${s.ref}]`) ? original : direct;
159
- }),
158
+ const projected = messages.some(isProjected);
159
+ // After an aligned projection, only host-edited messages can match a source by content: the others are
160
+ // tagged, sourceless (summaries, multi-message entries), or generated after the projection.
161
+ const contentOnly = (message) => !projected || isHostEdited(message);
162
+ const direct = messages.map((message) => {
163
+ const id = projectedEntryId(message);
164
+ const source = id === undefined ? undefined : this.byRef.get(refFor(id));
165
+ return source && (!this.activeIds || this.activeIds.has(source.entry.id)) ? source : undefined;
166
+ });
167
+ const used = new Set(direct.flatMap((source) => (source ? [source.ref] : []))),
168
+ hashes = messages.map((message, index) =>
169
+ direct[index] || !contentOnly(message) ? undefined : bodyHash(message),
170
+ ),
160
171
  remaining = new Map();
161
- for (const hash of hashes) remaining.set(hash, (remaining.get(hash) ?? 0) + 1);
172
+ for (const hash of hashes) if (hash) remaining.set(hash, (remaining.get(hash) ?? 0) + 1);
162
173
  const items = messages.map((message, index) => {
174
+ if (direct[index]) {
175
+ const source = direct[index];
176
+ source.active = true;
177
+ return { message, source };
178
+ }
179
+ if (hashes[index] === undefined) return { message };
163
180
  const hash = hashes[index],
164
181
  count = remaining.get(hash);
165
182
  remaining.set(hash, count - 1);
166
- const candidates = (this.byBody.get(hash) ?? []).filter(
183
+ const candidates = (this.bodyIndex().get(hash) ?? []).filter(
167
184
  (s) => !used.has(s.ref) && (!this.activeIds || this.activeIds.has(s.entry.id)),
168
185
  );
169
186
  const exact = candidates.find((s) => s.message === message);
170
187
  const source = exact ?? (candidates.length === 1 || candidates.length === count ? candidates[0] : undefined);
171
188
  if (!source) {
172
- for (const candidate of candidates) {
173
- this.ambiguous.add(candidate.ref);
174
- this.ambiguous.add(textRef(candidate.ref));
175
- }
189
+ for (const candidate of candidates) this.ambiguous.add(candidate.ref);
176
190
  return { message };
177
191
  }
178
192
  used.add(source.ref);
179
193
  source.active = true;
180
- const text = this.byRef.get(textRef(source.ref));
181
- if (text) text.active = true;
182
194
  return { message, source };
183
195
  });
184
196
  this.associated = { messages: [...messages], items };
@@ -188,8 +200,7 @@ export class Sources {
188
200
  const source = this.byRef.get(ref);
189
201
  if (!idFor(ref) || !source)
190
202
  return { ref, code: "source_unavailable", detail: "Exact source is unavailable on current native ancestry." };
191
- const original = source.original ?? source;
192
- if (bodyHash(original.message) !== original.hash || bodyHash(source.message) !== source.hash)
203
+ if (bodyHash(source.message) !== source.hash)
193
204
  return {
194
205
  ref,
195
206
  code: "source_changed",
@@ -197,7 +208,7 @@ export class Sources {
197
208
  };
198
209
  if (!isWorkerProfile(source.producer))
199
210
  return { ref, code: "source_origin", detail: "Selection requires observed worker attribution." };
200
- if (state.exposure.get(original.ref) !== original.hash && state.exposure.get(source.ref) !== source.hash)
211
+ if (state.exposure.get(source.ref) !== source.hash)
201
212
  return {
202
213
  ref,
203
214
  code: "source_unexposed",
@@ -210,17 +221,21 @@ export class Sources {
210
221
  if (problem) return problem;
211
222
  const source = this.byRef.get(ref);
212
223
  if (!isTaskEvidence(source))
213
- return {
214
- ref,
215
- code: "routing_source",
216
- detail: this.byRef.has(textRef(ref))
217
- ? `Routing control messages are not task evidence. Use ${textRef(ref)} if its visible assistant text is the intended evidence.`
218
- : "Routing control receipts are not task evidence; saved communication is delivered separately.",
219
- };
224
+ return source.message.role === "assistant"
225
+ ? {
226
+ ref,
227
+ code: "assistant_message",
228
+ detail:
229
+ "Assistant messages are not task evidence; say it in the report and select the tool results it rests on.",
230
+ }
231
+ : {
232
+ ref,
233
+ code: "routing_source",
234
+ detail: "Routing control receipts are not task evidence; saved communication is delivered separately.",
235
+ };
220
236
  return undefined;
221
237
  }
222
238
  exchange(source) {
223
- if (source.original) return { sources: [source], problems: [] };
224
239
  if (!["assistant", "toolResult"].includes(source.message.role)) return { sources: [source], problems: [] };
225
240
  const group = source.message.role === "assistant" ? this.exchanges.get(source.ref) : this.owners.get(source.ref);
226
241
  const calls = group?.assistant.message.content?.filter((b) => b.type === "toolCall") ?? [];
@@ -257,7 +272,7 @@ export class Sources {
257
272
  }
258
273
  locator(ref) {
259
274
  const source = this.byRef.get(ref);
260
- if (!source || source.original || source.message.role !== "toolResult") return undefined;
275
+ if (!source || source.message.role !== "toolResult") return undefined;
261
276
  const group = this.owners.get(source.ref);
262
277
  if (!group) return undefined;
263
278
  const calls = group.assistant.message.content?.filter((b) => b.type === "toolCall") ?? [];
@@ -266,12 +281,36 @@ export class Sources {
266
281
  );
267
282
  return matches.length === 1 ? locatorForCall(group.assistant, matches[0], this.locatorProvider) : undefined;
268
283
  }
284
+ /**
285
+ * What a tool result's call did, in a few words: its path, command or first short string argument. Coordinator
286
+ * matches a selected ref to the result in its view by this label (Task 004 S-005); undefined when unknown.
287
+ */
288
+ callLabel(ref) {
289
+ const source = this.byRef.get(ref);
290
+ if (!source || source.message.role !== "toolResult") return undefined;
291
+ const call = (this.owners.get(source.ref)?.assistant.message.content ?? []).find(
292
+ (block) =>
293
+ block.type === "toolCall" && block.id === source.message.toolCallId && block.name === source.message.toolName,
294
+ );
295
+ const args = call?.arguments;
296
+ if (!args || typeof args !== "object") return undefined;
297
+ // A path keeps its end, where the file name is; anything else keeps its start.
298
+ const path = typeof args.path === "string" ? args.path.trim() : "";
299
+ if (path) return path.length > 100 ? `...${path.slice(-97)}` : path;
300
+ const chosen =
301
+ ["command", "pattern", "query", "url"]
302
+ .map((key) => args[key])
303
+ .find((value) => typeof value === "string" && value.trim()) ??
304
+ Object.values(args).find((value) => typeof value === "string" && value.trim() && value.length <= 200);
305
+ const label = normalizeLabel(chosen)?.label;
306
+ if (!label) return undefined;
307
+ return label.length > 100 ? `${label.slice(0, 97)}...` : label;
308
+ }
269
309
  ordered(sources) {
270
310
  const ids = new Set([...sources].map((s) => s.ref));
271
- return this.entries.flatMap((entry) =>
272
- [this.byRef.get(refFor(entry.id)), this.byRef.get(textRef(refFor(entry.id)))].filter(
273
- (s) => !!s && ids.has(s.ref),
274
- ),
275
- );
311
+ return this.entries.flatMap((entry) => {
312
+ const source = this.byRef.get(refFor(entry.id));
313
+ return source && ids.has(source.ref) ? [source] : [];
314
+ });
276
315
  }
277
316
  }