@hassangameryt/freeflow 0.5.0 → 0.7.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 (301) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +4 -5
  4. package/README.md +141 -163
  5. package/capabilities/cognitive-routing/SKILL.md +387 -0
  6. package/capabilities/context-virtualization/SKILL.md +103 -0
  7. package/capabilities/conversation-history/SKILL.md +53 -0
  8. package/command-surface.json +6 -37
  9. package/hooks/freeflow-runtime-context.mjs +50 -541
  10. package/hooks/hooks.json +1 -26
  11. package/hooks/tests/check-runtime-context-hook.sh +114 -308
  12. package/package.json +27 -17
  13. package/pi-extension/dist/cognitive-routing/commands.js +96 -0
  14. package/pi-extension/dist/cognitive-routing/config.js +232 -0
  15. package/pi-extension/dist/cognitive-routing/controller.js +1292 -0
  16. package/pi-extension/dist/cognitive-routing/history.js +451 -0
  17. package/pi-extension/dist/cognitive-routing/host.js +188 -0
  18. package/pi-extension/dist/cognitive-routing/pi-routing-session.js +414 -0
  19. package/pi-extension/dist/cognitive-routing/pi-session-control.js +320 -0
  20. package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
  21. package/pi-extension/dist/cognitive-routing/tool.js +212 -0
  22. package/pi-extension/dist/cognitive-routing/types.js +6 -0
  23. package/pi-extension/dist/context-virtualization/commands.js +89 -0
  24. package/pi-extension/dist/context-virtualization/projector.js +42 -0
  25. package/pi-extension/dist/context-virtualization/runtime.js +356 -0
  26. package/pi-extension/dist/context-virtualization/state.js +57 -0
  27. package/pi-extension/dist/context-virtualization/types.js +10 -0
  28. package/pi-extension/dist/conversation-history/passages.js +66 -0
  29. package/pi-extension/dist/conversation-history/ranking.js +105 -0
  30. package/pi-extension/dist/conversation-history/runtime.js +226 -0
  31. package/pi-extension/dist/conversation-history/search.js +56 -0
  32. package/pi-extension/dist/conversation-history/types.js +1 -0
  33. package/pi-extension/dist/freeflow-context/resolver.js +120 -0
  34. package/pi-extension/dist/freeflow-context/runtime.js +80 -0
  35. package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
  36. package/pi-extension/dist/freeflow-context/tool.js +308 -0
  37. package/pi-extension/dist/freeflow-context/types.js +12 -0
  38. package/pi-extension/dist/freeflow-context/visibility.js +28 -0
  39. package/pi-extension/dist/index.js +564 -129
  40. package/pi-extension/dist/runtime/runtime-context.js +357 -470
  41. package/pi-extension/dist/runtime/runtime-identity.js +5 -0
  42. package/pi-extension/dist/settings/settings-tui.js +78 -0
  43. package/pi-extension/dist/settings/settings-ui.js +572 -826
  44. package/pi-extension/dist/ui/text-component.js +57 -0
  45. package/pi-extension/src/cognitive-routing/commands.ts +129 -0
  46. package/pi-extension/src/cognitive-routing/config.ts +303 -0
  47. package/pi-extension/src/cognitive-routing/controller.ts +1628 -0
  48. package/pi-extension/src/cognitive-routing/history.ts +650 -0
  49. package/pi-extension/src/cognitive-routing/host.ts +266 -0
  50. package/pi-extension/src/cognitive-routing/pi-routing-session.ts +538 -0
  51. package/pi-extension/src/cognitive-routing/pi-session-control.ts +444 -0
  52. package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
  53. package/pi-extension/src/cognitive-routing/tool.ts +273 -0
  54. package/pi-extension/src/cognitive-routing/types.ts +89 -0
  55. package/pi-extension/src/context-virtualization/commands.ts +111 -0
  56. package/pi-extension/src/context-virtualization/projector.ts +62 -0
  57. package/pi-extension/src/context-virtualization/runtime.ts +406 -0
  58. package/pi-extension/src/context-virtualization/state.ts +79 -0
  59. package/pi-extension/src/context-virtualization/types.ts +92 -0
  60. package/pi-extension/src/conversation-history/passages.ts +81 -0
  61. package/pi-extension/src/conversation-history/ranking.ts +155 -0
  62. package/pi-extension/src/conversation-history/runtime.ts +250 -0
  63. package/pi-extension/src/conversation-history/search.ts +79 -0
  64. package/pi-extension/src/conversation-history/types.ts +31 -0
  65. package/pi-extension/src/freeflow-context/resolver.ts +139 -0
  66. package/pi-extension/src/freeflow-context/runtime.ts +100 -0
  67. package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
  68. package/pi-extension/src/freeflow-context/tool.ts +360 -0
  69. package/pi-extension/src/freeflow-context/types.ts +70 -0
  70. package/pi-extension/src/freeflow-context/visibility.ts +53 -0
  71. package/pi-extension/src/index.ts +597 -135
  72. package/pi-extension/src/runtime/runtime-context.ts +373 -491
  73. package/pi-extension/src/runtime/runtime-identity.ts +8 -0
  74. package/pi-extension/src/settings/settings-tui.ts +93 -0
  75. package/pi-extension/src/settings/settings-ui.ts +679 -910
  76. package/pi-extension/src/ui/text-component.ts +66 -0
  77. package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
  78. package/pi-extension/tests/cognitive-routing/controller.test.js +1128 -0
  79. package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1142 -0
  80. package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
  81. package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
  82. package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
  83. package/pi-extension/tests/cognitive-routing/pi-normal-lifecycle.test.js +434 -0
  84. package/pi-extension/tests/cognitive-routing/pi-session-control.test.js +174 -0
  85. package/pi-extension/tests/cognitive-routing/pi-session-history.test.js +91 -0
  86. package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +279 -0
  87. package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
  88. package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
  89. package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
  90. package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
  91. package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
  92. package/pi-extension/tests/conversation-history/search.test.js +97 -0
  93. package/pi-extension/tests/integration/mode-free-core.test.js +218 -0
  94. package/pi-extension/tests/integration/pi-extension.test.js +532 -3701
  95. package/pi-extension/tests/integration/prompt-architecture.test.js +350 -0
  96. package/pi-extension/tests/integration/unaffected-regressions.test.js +411 -0
  97. package/runtime/prompts/cognitive-routing.md +10 -0
  98. package/runtime/prompts/context-virtualization.md +3 -0
  99. package/runtime/prompts/conversation-history.md +3 -0
  100. package/runtime/prompts/core.md +84 -0
  101. package/runtime/prompts/interaction-contract.md +11 -0
  102. package/skills/action-selection/SKILL.md +140 -0
  103. package/skills/action-selection/references/trajectory-stalls.md +71 -0
  104. package/skills/bypass/SKILL.md +109 -38
  105. package/skills/commit-work/SKILL.md +94 -55
  106. package/skills/commit-work/references/git-state-edges.md +94 -0
  107. package/skills/commit-work/references/simple-push.md +92 -0
  108. package/skills/commit-work/references/staging-decisions.md +79 -46
  109. package/skills/decision-gate/SKILL.md +80 -22
  110. package/skills/design-for-depth/SKILL.md +206 -60
  111. package/skills/design-for-depth/references/design-pressure-signals.md +108 -240
  112. package/skills/design-for-depth/references/interface-design-loop.md +77 -97
  113. package/skills/design-for-depth/references/module-and-dependency-design.md +147 -0
  114. package/skills/design-for-depth/references/software-design-philosophy.md +128 -174
  115. package/skills/design-for-depth/references/state-and-failure-boundaries.md +136 -0
  116. package/skills/diagnose-failure/SKILL.md +200 -48
  117. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +18 -6
  118. package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +13 -5
  119. package/skills/discuss/SKILL.md +119 -65
  120. package/skills/discuss/references/discussion-continuity.md +123 -0
  121. package/skills/evaluate-skill/SKILL.md +166 -52
  122. package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +43 -3
  123. package/skills/evaluate-skill/references/evaluation-design.md +56 -30
  124. package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
  125. package/skills/evaluate-skill/references/review-and-revision.md +62 -21
  126. package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
  127. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
  128. package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
  129. package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
  130. package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
  131. package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
  132. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
  133. package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
  134. package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
  135. package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
  136. package/skills/execute-work/SKILL.md +99 -57
  137. package/skills/execute-work/references/code-practices.md +4 -4
  138. package/skills/execute-work/references/execute-work-edges.md +62 -0
  139. package/skills/finish-branch/SKILL.md +2 -2
  140. package/skills/finish-branch/references/integration-options.md +1 -1
  141. package/skills/handoff/SKILL.md +3 -3
  142. package/skills/launch-work/SKILL.md +1 -1
  143. package/skills/launch-work/references/launch-readiness.md +2 -2
  144. package/skills/migration-work/SKILL.md +2 -2
  145. package/skills/migration-work/references/migration-lifecycle.md +1 -1
  146. package/skills/release-work/SKILL.md +1 -1
  147. package/skills/release-work/references/release-evidence.md +1 -1
  148. package/skills/review-artifact/SKILL.md +129 -66
  149. package/skills/review-artifact/references/adjudicate-artifact-review.md +101 -0
  150. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +159 -0
  151. package/skills/review-work/SKILL.md +113 -68
  152. package/skills/review-work/references/adjudicate-work-review.md +97 -0
  153. package/skills/review-work/references/independent-work-reviewer-contract.md +139 -0
  154. package/skills/review-work/references/security-risk-lens.md +18 -16
  155. package/skills/setup-freeflow/SKILL.md +16 -17
  156. package/skills/setup-freeflow/references/activation-contract.md +24 -30
  157. package/skills/setup-freeflow/references/host-setup.md +6 -7
  158. package/skills/simplify-code/SKILL.md +97 -39
  159. package/skills/simplify-code/references/simplification-patterns.md +1 -1
  160. package/skills/tdd/SKILL.md +100 -53
  161. package/skills/tdd/references/test-design.md +3 -3
  162. package/skills/track-work/SKILL.md +195 -58
  163. package/skills/track-work/references/working-record-format.md +515 -0
  164. package/skills/track-work/scripts/lib/document.mjs +713 -0
  165. package/skills/track-work/scripts/lib/format.mjs +166 -0
  166. package/skills/track-work/scripts/lib/store.mjs +233 -0
  167. package/skills/track-work/scripts/lib/transitions.mjs +790 -0
  168. package/skills/track-work/scripts/lib/views.mjs +40 -0
  169. package/skills/track-work/scripts/working-record.mjs +316 -0
  170. package/skills/verify-work/SKILL.md +57 -19
  171. package/skills/verify-work/references/browser-runtime-evidence.md +2 -2
  172. package/skills/verify-work/references/integration-evidence.md +1 -7
  173. package/skills/verify-work/references/performance-evidence.md +2 -2
  174. package/skills/workflow/SKILL.md +137 -55
  175. package/skills/workflow/references/domain-skill-composition.md +26 -40
  176. package/skills/write-plan/SKILL.md +1 -1
  177. package/skills/write-skill/SKILL.md +218 -61
  178. package/skills/write-skill/references/activation-boundaries.md +63 -21
  179. package/skills/write-skill/references/agent-first-instructions.md +61 -27
  180. package/skills/write-skill/references/progressive-disclosure.md +97 -33
  181. package/skills/write-skill/references/skill-dependency-graphs.md +190 -0
  182. package/capabilities/output-router/SKILL.md +0 -206
  183. package/capabilities/output-router/references/safety-policy.md +0 -40
  184. package/capabilities/output-router/references/setup.md +0 -110
  185. package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
  186. package/pi-extension/dist/output-router/native-safety-net.js +0 -216
  187. package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
  188. package/pi-extension/dist/output-router/renderers.js +0 -1023
  189. package/pi-extension/dist/output-router/router-tools.js +0 -554
  190. package/pi-extension/dist/output-router/schemas.js +0 -383
  191. package/pi-extension/dist/output-router/status.js +0 -744
  192. package/pi-extension/dist/output-router/utils.js +0 -502
  193. package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
  194. package/pi-extension/src/output-router/native-safety-net.ts +0 -248
  195. package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
  196. package/pi-extension/src/output-router/renderers.ts +0 -1108
  197. package/pi-extension/src/output-router/router-tools.ts +0 -579
  198. package/pi-extension/src/output-router/schemas.ts +0 -387
  199. package/pi-extension/src/output-router/status.ts +0 -791
  200. package/pi-extension/src/output-router/utils.ts +0 -554
  201. package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
  202. package/pi-extension/tests/output-router/search.test.js +0 -722
  203. package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
  204. package/router/dist/benchmarks/benchmark-harness.js +0 -92
  205. package/router/dist/benchmarks/benchmarks.d.ts +0 -109
  206. package/router/dist/benchmarks/benchmarks.js +0 -979
  207. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
  208. package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
  209. package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
  210. package/router/dist/benchmarks/command-benchmarks.js +0 -698
  211. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
  212. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
  213. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
  214. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
  215. package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
  216. package/router/dist/benchmarks/context-saving-baseline.js +0 -470
  217. package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
  218. package/router/dist/benchmarks/index-benchmarks.js +0 -862
  219. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
  220. package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
  221. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
  222. package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
  223. package/router/dist/config/config.d.ts +0 -103
  224. package/router/dist/config/config.js +0 -632
  225. package/router/dist/config/router-contract.d.ts +0 -10
  226. package/router/dist/config/router-contract.js +0 -54
  227. package/router/dist/config/schema.d.ts +0 -27
  228. package/router/dist/config/schema.js +0 -648
  229. package/router/dist/config/types.d.ts +0 -573
  230. package/router/dist/config/types.js +0 -41
  231. package/router/dist/evidence/bounded-evidence.d.ts +0 -40
  232. package/router/dist/evidence/bounded-evidence.js +0 -323
  233. package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
  234. package/router/dist/evidence/evidence-range-selector.js +0 -232
  235. package/router/dist/evidence/evidence-search.d.ts +0 -27
  236. package/router/dist/evidence/evidence-search.js +0 -490
  237. package/router/dist/evidence/evidence.d.ts +0 -38
  238. package/router/dist/evidence/evidence.js +0 -200
  239. package/router/dist/evidence/failure-contracts.d.ts +0 -37
  240. package/router/dist/evidence/failure-contracts.js +0 -166
  241. package/router/dist/evidence/line-ranges.d.ts +0 -24
  242. package/router/dist/evidence/line-ranges.js +0 -22
  243. package/router/dist/experiments/local-index.d.ts +0 -64
  244. package/router/dist/experiments/local-index.js +0 -581
  245. package/router/dist/index.d.ts +0 -30
  246. package/router/dist/index.js +0 -32
  247. package/router/dist/local/local-traversal.d.ts +0 -18
  248. package/router/dist/local/local-traversal.js +0 -334
  249. package/router/dist/processing/engine.d.ts +0 -132
  250. package/router/dist/processing/engine.js +0 -533
  251. package/router/dist/processing/reducers.d.ts +0 -280
  252. package/router/dist/processing/reducers.js +0 -1673
  253. package/router/dist/processing/renderers.d.ts +0 -31
  254. package/router/dist/processing/renderers.js +0 -195
  255. package/router/dist/processing/scripts.d.ts +0 -91
  256. package/router/dist/processing/scripts.js +0 -386
  257. package/router/dist/repo/repo-traversal.d.ts +0 -18
  258. package/router/dist/repo/repo-traversal.js +0 -245
  259. package/router/dist/routing/observed-reducers.d.ts +0 -41
  260. package/router/dist/routing/observed-reducers.js +0 -661
  261. package/router/dist/routing/observed-routing.d.ts +0 -26
  262. package/router/dist/routing/observed-routing.js +0 -378
  263. package/router/dist/routing/parsers.d.ts +0 -16
  264. package/router/dist/routing/parsers.js +0 -521
  265. package/router/dist/routing/run-filters.d.ts +0 -60
  266. package/router/dist/routing/run-filters.js +0 -238
  267. package/router/dist/routing/run-reducers.d.ts +0 -49
  268. package/router/dist/routing/run-reducers.js +0 -122
  269. package/router/dist/sandbox/adapter-roots.d.ts +0 -46
  270. package/router/dist/sandbox/adapter-roots.js +0 -66
  271. package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
  272. package/router/dist/sandbox/eryx-python-adapter.js +0 -868
  273. package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
  274. package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
  275. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
  276. package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
  277. package/router/dist/sandbox/script-sandbox.d.ts +0 -134
  278. package/router/dist/sandbox/script-sandbox.js +0 -337
  279. package/router/dist/setup/script-transform-adapters.d.ts +0 -32
  280. package/router/dist/setup/script-transform-adapters.js +0 -278
  281. package/router/dist/tools/batch.d.ts +0 -33
  282. package/router/dist/tools/batch.js +0 -586
  283. package/router/dist/tools/run.d.ts +0 -62
  284. package/router/dist/tools/run.js +0 -1304
  285. package/router/dist/tools/search.d.ts +0 -66
  286. package/router/dist/tools/search.js +0 -1364
  287. package/router/dist/transform/engine.d.ts +0 -168
  288. package/router/dist/transform/engine.js +0 -2072
  289. package/router/dist/vault/vault-index.d.ts +0 -125
  290. package/router/dist/vault/vault-index.js +0 -416
  291. package/router/dist/vault/vault.d.ts +0 -138
  292. package/router/dist/vault/vault.js +0 -630
  293. package/runtime/interaction-contract.md +0 -16
  294. package/skills/discuss/references/checkpoints.md +0 -66
  295. package/skills/execute-work/references/execution-loop.md +0 -77
  296. package/skills/mode-contract/SKILL.md +0 -104
  297. package/skills/review-artifact/references/reviewer-prompt.md +0 -148
  298. package/skills/review-work/references/reviewer-prompt.md +0 -134
  299. package/skills/track-work/references/working-record-schema.md +0 -378
  300. package/skills/workflow/references/workflow-loop.md +0 -92
  301. /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
@@ -1,35 +1,157 @@
1
- import { handleNativeToolSafetyNet } from "./output-router/native-safety-net.js";
2
- import { handleObservedToolRouting } from "./output-router/observed-tool-routing.js";
3
- import { registerRouterTools } from "./output-router/router-tools.js";
4
- import { handleFreeflowCommand, handleOutputRouterCommand } from "./settings/settings-ui.js";
1
+ import {
2
+ COGNITIVE_ROUTING_CONTROL_ENTRY,
3
+ COGNITIVE_ROUTING_INACTIVE_ENTRY,
4
+ COGNITIVE_ROUTING_INTENT_ENTRY,
5
+ } from "./cognitive-routing/controller.js";
6
+ import { PiRoutingSession } from "./cognitive-routing/pi-routing-session.js";
7
+ import {
8
+ cognitiveRoutingProfileCompletions,
9
+ handleCognitiveRoutingProfileCommand,
10
+ } from "./cognitive-routing/commands.js";
11
+ import { registerCognitiveRoutingHistoryTool, registerCognitiveRoutingTool } from "./cognitive-routing/tool.js";
12
+ import { readCognitiveRoutingHistory } from "./cognitive-routing/history.js";
13
+ import { ConversationHistoryRuntime } from "./conversation-history/runtime.js";
14
+ import { FreeflowContextRuntime } from "./freeflow-context/runtime.js";
15
+ import { CONTEXT_VIRTUALIZATION_TOOL_NAME, registerFreeflowContextTool } from "./freeflow-context/tool.js";
16
+ import { handleContextCommand } from "./context-virtualization/commands.js";
17
+ import { ContextVirtualizationRuntime } from "./context-virtualization/runtime.js";
18
+ import { handleFreeflowCommand } from "./settings/settings-ui.js";
19
+ import { isPiFlowHost } from "./runtime/runtime-identity.js";
5
20
  import {
6
21
  CONTRIBUTOR_COMMANDS,
22
+ COGNITIVE_ROUTING_SWITCH_TOOL_NAME,
7
23
  WORKFLOW_COMMANDS,
8
- WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
9
- FREEFLOW_STATUS_TOOL_NAME,
10
24
  freeflowModelSkillPaths,
11
25
  freeflowSkillPath,
12
26
  getRuntimeContext,
13
- OUTPUT_ROUTER_TOOL_NAMES,
27
+ hasUsableMandatoryPrompts,
28
+ isPromptAvailable,
14
29
  readCapabilityState,
15
- readModeState,
16
- readOutputRouterConfig,
17
30
  refreshRuntimeContext,
18
- restoreModeOverride,
31
+ restoreSessionOverrides,
19
32
  runtimeContext,
20
- workflowBootstrapMessage,
21
- setModeStatus,
33
+ filterBootstrapMessage,
34
+ setFreeflowStatus,
22
35
  skillPrompt,
23
- notifyRouterConfigWarnings,
36
+ withFreeflowRuntimeState,
24
37
  } from "./runtime/runtime-context.js";
25
- function isOutputRouterToolName(name) {
26
- return OUTPUT_ROUTER_TOOL_NAMES.includes(name);
38
+ function unavailableCapability(capability, code, message) {
39
+ return {
40
+ ...capability,
41
+ effective: false,
42
+ blockingReason: { code, message },
43
+ };
27
44
  }
28
- async function applyCapabilityToolVisibility(pi, ctx, capabilityState = undefined) {
29
- if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") {
30
- return;
45
+ function modelFacingCapabilityState(
46
+ capabilityState,
47
+ freeflowContext,
48
+ routingSnapshot,
49
+ cognitiveRoutingActivationFailed = false,
50
+ ) {
51
+ const surfaceState = {
52
+ ...capabilityState,
53
+ contextVirtualization: { ...capabilityState?.contextVirtualization },
54
+ conversationHistory: { ...capabilityState?.conversationHistory },
55
+ cognitiveRouting: { ...capabilityState?.cognitiveRouting },
56
+ };
57
+ if (surfaceState.enabled !== true) return surfaceState;
58
+ const markUnavailable = (key, message) => {
59
+ if (surfaceState[key]?.effective === true) {
60
+ surfaceState[key] = unavailableCapability(surfaceState[key], "unavailable", message);
61
+ }
62
+ };
63
+ if (!hasUsableMandatoryPrompts(freeflowContext)) {
64
+ for (const key of ["contextVirtualization", "conversationHistory", "cognitiveRouting"]) {
65
+ markUnavailable(key, "Mandatory Freeflow prompt is unavailable.");
66
+ }
67
+ return surfaceState;
68
+ }
69
+ if (
70
+ surfaceState.contextVirtualization?.effective === true &&
71
+ !isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
72
+ ) {
73
+ markUnavailable("contextVirtualization", "Context Virtualization prompt is unavailable.");
31
74
  }
32
- const state = capabilityState ?? (await readCapabilityState(ctx.cwd));
75
+ if (
76
+ surfaceState.conversationHistory?.effective === true &&
77
+ !isPromptAvailable(freeflowContext.conversationHistoryPrompt)
78
+ ) {
79
+ markUnavailable("conversationHistory", "Conversation History prompt is unavailable.");
80
+ }
81
+ if (surfaceState.cognitiveRouting?.effective === true) {
82
+ const controllerState = routingSnapshot.runtimeState;
83
+ if (routingSnapshot.disposition === "blocked") {
84
+ surfaceState.cognitiveRouting = unavailableCapability(
85
+ surfaceState.cognitiveRouting,
86
+ "runtime_blocked",
87
+ routingSnapshot.reason ?? "Cognitive Routing is blocked because its inactive state could not be persisted.",
88
+ );
89
+ } else if (routingSnapshot.startupSelectionSuppressed || routingSnapshot.disposition === "inactive") {
90
+ surfaceState.cognitiveRouting = unavailableCapability(
91
+ surfaceState.cognitiveRouting,
92
+ "runtime_inactive",
93
+ "Cognitive Routing is inactive because Pi owns the startup model or thinking level.",
94
+ );
95
+ } else if (controllerState?.runtimeStatus === "inactive") {
96
+ surfaceState.cognitiveRouting = unavailableCapability(
97
+ surfaceState.cognitiveRouting,
98
+ "runtime_inactive",
99
+ controllerState.runtimeReason ?? "Cognitive Routing is inactive because Pi owns the current model state.",
100
+ );
101
+ } else if (controllerState?.runtimeStatus === "blocked") {
102
+ surfaceState.cognitiveRouting = unavailableCapability(
103
+ surfaceState.cognitiveRouting,
104
+ "runtime_blocked",
105
+ controllerState.runtimeReason ?? "Cognitive Routing is blocked because its state is not proven.",
106
+ );
107
+ } else if (cognitiveRoutingActivationFailed || controllerState?.effective === false) {
108
+ surfaceState.cognitiveRouting = unavailableCapability(
109
+ surfaceState.cognitiveRouting,
110
+ "unavailable",
111
+ "Cognitive Routing could not activate for this session.",
112
+ );
113
+ } else if (!isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)) {
114
+ markUnavailable("cognitiveRouting", "Cognitive Routing prompt is unavailable.");
115
+ }
116
+ }
117
+ return surfaceState;
118
+ }
119
+ function sessionHasConversationOrRoutingState(ctx) {
120
+ try {
121
+ const entries = ctx?.sessionManager?.getBranch?.() ?? ctx?.sessionManager?.getEntries?.() ?? [];
122
+ if (!Array.isArray(entries)) return false;
123
+ return entries.some((entry) => {
124
+ if (!entry || typeof entry !== "object") return false;
125
+ const record = entry;
126
+ if (
127
+ typeof record.type === "string" &&
128
+ ["message", "custom_message", "compaction", "branch_summary"].includes(record.type)
129
+ ) {
130
+ return true;
131
+ }
132
+ return (
133
+ record.type === "custom" &&
134
+ (record.customType === COGNITIVE_ROUTING_INTENT_ENTRY ||
135
+ record.customType === COGNITIVE_ROUTING_CONTROL_ENTRY ||
136
+ record.customType === COGNITIVE_ROUTING_INACTIVE_ENTRY)
137
+ );
138
+ });
139
+ } catch {
140
+ return false;
141
+ }
142
+ }
143
+ async function applyCapabilityToolVisibility(
144
+ pi,
145
+ ctx,
146
+ capabilityState = undefined,
147
+ routingSnapshot = {
148
+ status: "available",
149
+ disposition: "available",
150
+ startupSelectionSuppressed: false,
151
+ },
152
+ ) {
153
+ if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") return;
154
+ const state = capabilityState ?? (await readCapabilityState(ctx.cwd, ctx, pi?.host));
33
155
  const allToolNames = pi
34
156
  .getAllTools()
35
157
  .map((tool) => tool?.name)
@@ -39,23 +161,24 @@ async function applyCapabilityToolVisibility(pi, ctx, capabilityState = undefine
39
161
  const active = new Set(
40
162
  (Array.isArray(currentActive) ? currentActive : allToolNames).filter((name) => allToolNameSet.has(name)),
41
163
  );
42
- if (allToolNameSet.has(FREEFLOW_STATUS_TOOL_NAME)) {
43
- if (state.configured && state.enabled) active.add(FREEFLOW_STATUS_TOOL_NAME);
44
- else active.delete(FREEFLOW_STATUS_TOOL_NAME);
164
+ if (allToolNameSet.has(COGNITIVE_ROUTING_SWITCH_TOOL_NAME)) {
165
+ const controllerState = routingSnapshot.runtimeState;
166
+ const routingToolActive =
167
+ state.cognitiveRouting?.effective === true &&
168
+ controllerState?.effective === true &&
169
+ controllerState.controlMode === "automatic";
170
+ if (routingToolActive) active.add(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
171
+ else active.delete(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
45
172
  }
46
- for (const toolName of OUTPUT_ROUTER_TOOL_NAMES) {
47
- if (!allToolNameSet.has(toolName)) continue;
48
- if (state.outputRouter.enabled) active.add(toolName);
49
- else active.delete(toolName);
173
+ if (allToolNameSet.has(CONTEXT_VIRTUALIZATION_TOOL_NAME)) {
174
+ if (state.contextVirtualization?.effective === true || state.conversationHistory?.effective === true) {
175
+ active.add(CONTEXT_VIRTUALIZATION_TOOL_NAME);
176
+ } else {
177
+ active.delete(CONTEXT_VIRTUALIZATION_TOOL_NAME);
178
+ }
50
179
  }
51
180
  pi.setActiveTools([...active]);
52
181
  }
53
- async function applyLiveCapabilityState(pi, ctx) {
54
- const [modeState, capabilityState] = await Promise.all([readModeState(ctx.cwd), readCapabilityState(ctx.cwd)]);
55
- await refreshRuntimeContext(capabilityState);
56
- setModeStatus(ctx, modeState, capabilityState);
57
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
58
- }
59
182
  function disabledToolCall(toolName, capability) {
60
183
  const command = capability === "freeflow" ? "/freeflow settings" : `/${capability} settings`;
61
184
  return {
@@ -63,16 +186,7 @@ function disabledToolCall(toolName, capability) {
63
186
  reason: `${toolName} is disabled by Freeflow config. Configure ${capability} with ${command}.`,
64
187
  };
65
188
  }
66
- function capabilityCompletions(prefix) {
67
- const query = prefix ?? "";
68
- return [
69
- { value: "settings", label: "settings", description: "Open repository Output Router settings" },
70
- { value: "status", label: "status", description: "Show effective Output Router state" },
71
- { value: "enable", label: "enable", description: "Enable Output Router for this repository" },
72
- { value: "disable", label: "disable", description: "Disable Output Router for this repository" },
73
- ].filter((item) => item.value.startsWith(query));
74
- }
75
- function freeflowCompletions(prefix) {
189
+ function freeflowCompletions(prefix, cognitiveRoutingAvailable = false) {
76
190
  const query = prefix ?? "";
77
191
  if (query.startsWith("settings ")) {
78
192
  const settingsQuery = query.slice("settings ".length);
@@ -84,25 +198,30 @@ function freeflowCompletions(prefix) {
84
198
  .filter((item) => item.value.startsWith(settingsQuery))
85
199
  .map((item) => ({ ...item, value: `settings ${item.value}` }));
86
200
  }
87
- if (query.startsWith("mode ")) {
88
- const modeQuery = query.slice("mode ".length);
201
+ if (cognitiveRoutingAvailable && query.startsWith("profile ")) {
202
+ return cognitiveRoutingProfileCompletions(query.slice("profile ".length)).map((item) => ({
203
+ ...item,
204
+ value: `profile ${item.value}`,
205
+ }));
206
+ }
207
+ if (query.startsWith("context ")) {
208
+ const contextQuery = query.slice("context ".length);
89
209
  return [
90
- { value: "conversation", label: "conversation", description: "Read-only discussion and inspection" },
91
- { value: "workflow", label: "workflow", description: "Adaptive workflow for consequential work" },
92
- { value: "strict-workflow", label: "strict-workflow", description: "Stronger pressure at high-risk boundaries" },
93
- {
94
- value: "reset",
95
- label: "reset",
96
- description: "Clear the session override and use the configured default",
97
- },
210
+ { value: "status", label: "status", description: "Show Freeflow Context state" },
211
+ { value: "list", label: "list", description: "List archived context projections" },
212
+ { value: "restore", label: "restore", description: "Restore one or more context references" },
213
+ { value: "reset all", label: "reset all", description: "Reset projection decisions on the active branch" },
98
214
  ]
99
- .filter((item) => item.value.startsWith(modeQuery))
100
- .map((item) => ({ ...item, value: `mode ${item.value}` }));
215
+ .filter((item) => item.value.startsWith(contextQuery))
216
+ .map((item) => ({ ...item, value: `context ${item.value}` }));
101
217
  }
102
218
  return [
103
219
  { value: "settings", label: "settings", description: "Open personal override settings" },
104
220
  { value: "status", label: "status", description: "Show effective Freeflow state" },
105
- { value: "mode", label: "mode", description: "Select a temporary session mode" },
221
+ { value: "context", label: "context", description: "Inspect Freeflow Context" },
222
+ ...(cognitiveRoutingAvailable
223
+ ? [{ value: "profile", label: "profile", description: "Hold or release Cognitive Routing profile control" }]
224
+ : []),
106
225
  { value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
107
226
  { value: "disable", label: "disable", description: "Disable Freeflow for this repository" },
108
227
  ].filter((item) => item.value.startsWith(query));
@@ -115,9 +234,9 @@ function bypassCompletions(prefix) {
115
234
  ].filter((item) => item.value.startsWith(query));
116
235
  }
117
236
  async function sendSkillCommand(pi, ctx, skill, args) {
118
- const state = await readCapabilityState(ctx.cwd);
237
+ const state = await readCapabilityState(ctx.cwd, ctx, pi?.host);
119
238
  if (skill === "setup-freeflow" && !state.configured) {
120
- await pi.sendUserMessage(skillPrompt(skill, args));
239
+ await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
121
240
  return;
122
241
  }
123
242
  if (!state.configured) {
@@ -131,100 +250,383 @@ async function sendSkillCommand(pi, ctx, skill, args) {
131
250
  );
132
251
  return;
133
252
  }
134
- if (!state.skills.effective) {
135
- ctx.ui.notify("Freeflow skills are disabled. Use /freeflow settings to enable skills.", "warning");
253
+ const freeflowContext = await getRuntimeContext(state);
254
+ if (!hasUsableMandatoryPrompts(freeflowContext)) {
255
+ ctx.ui.notify("Freeflow core prompts are unavailable; the requested skill cannot be dispatched.", "warning");
136
256
  return;
137
257
  }
138
- await pi.sendUserMessage(skillPrompt(skill, args));
258
+ await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
139
259
  }
140
260
  export default function freeflow(pi) {
141
- registerRouterTools(pi);
261
+ // SAFETY: These helpers register complete Pi tool definitions but retain legacy structural typing for PiFlow compatibility.
262
+ const toolRegistrar = pi;
263
+ const routingSession = new PiRoutingSession({ pi, stockPi: !isPiFlowHost(pi?.host) });
264
+ let latestCognitiveRoutingContext;
265
+ let providerSurfaceSnapshot;
266
+ let runtimeStateRefreshRequired = true;
267
+ let freeflowContextRuntime;
268
+ let contextVirtualizationRuntime;
269
+ let conversationHistoryRuntime;
270
+ const registerContextToolForState = (capabilityState) => {
271
+ registerFreeflowContextTool(
272
+ toolRegistrar,
273
+ () => contextVirtualizationRuntime,
274
+ () => conversationHistoryRuntime,
275
+ {
276
+ contextVirtualization: capabilityState?.contextVirtualization?.effective === true,
277
+ conversationHistory: capabilityState?.conversationHistory?.effective === true,
278
+ },
279
+ );
280
+ };
281
+ const buildProviderSurface = async (ctx, activateCognitiveRouting = false) => {
282
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
283
+ const freeflowContext = await getRuntimeContext(capabilityState);
284
+ const promptCapabilityState = modelFacingCapabilityState(
285
+ capabilityState,
286
+ freeflowContext,
287
+ routingSession.snapshot(),
288
+ );
289
+ let activationAttempted = false;
290
+ if (
291
+ activateCognitiveRouting &&
292
+ routingSession.canAutoActivate() &&
293
+ (!routingSession.hasController() || promptCapabilityState.cognitiveRouting?.effective !== true)
294
+ ) {
295
+ activationAttempted = promptCapabilityState.cognitiveRouting?.effective === true;
296
+ try {
297
+ await routingSession.reconcileController(
298
+ ctx,
299
+ promptCapabilityState,
300
+ routingSession.armed ? { ...routingSession.armed } : undefined,
301
+ );
302
+ if (routingSession.hasController()) {
303
+ routingSession.clearArmed();
304
+ if (routingSession.snapshot().status === "active") routingSession.markActive();
305
+ }
306
+ } catch {
307
+ routingSession.clearController();
308
+ }
309
+ }
310
+ const surfaceCapabilityState = modelFacingCapabilityState(
311
+ promptCapabilityState,
312
+ freeflowContext,
313
+ routingSession.snapshot(),
314
+ activationAttempted && !routingSession.hasController(),
315
+ );
316
+ const routingSnapshot = routingSession.snapshot();
317
+ return {
318
+ capabilityState: surfaceCapabilityState,
319
+ freeflowContext,
320
+ cognitiveRoutingRuntime: routingSnapshot.runtimeState,
321
+ configuredCapabilityState: capabilityState,
322
+ };
323
+ };
324
+ const applyLiveCapabilityStateForSession = async (ctx, options = {}) => {
325
+ providerSurfaceSnapshot = undefined;
326
+ await routingSession.applyLiveCapabilityState(ctx, options);
327
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
328
+ const freeflowContext = await getRuntimeContext(capabilityState);
329
+ const surfaceCapabilityState = modelFacingCapabilityState(
330
+ capabilityState,
331
+ freeflowContext,
332
+ routingSession.snapshot(),
333
+ );
334
+ const routingSnapshot = routingSession.snapshot();
335
+ setFreeflowStatus(ctx, surfaceCapabilityState, routingSnapshot.runtimeState, freeflowContext, {
336
+ startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
337
+ });
338
+ await applyCapabilityToolVisibility(pi, ctx, surfaceCapabilityState, routingSnapshot);
339
+ registerContextToolForState(surfaceCapabilityState);
340
+ };
341
+ if (routingSession.supportsCognitiveRoutingRuntime()) {
342
+ registerCognitiveRoutingTool(toolRegistrar, () => routingSession.controllerForTool());
343
+ registerCognitiveRoutingHistoryTool(toolRegistrar, (options, context) => {
344
+ return (
345
+ routingSession.history(options) ??
346
+ readCognitiveRoutingHistory(context ?? latestCognitiveRoutingContext, options)
347
+ );
348
+ });
349
+ }
350
+ registerFreeflowContextTool(
351
+ toolRegistrar,
352
+ () => contextVirtualizationRuntime,
353
+ () => conversationHistoryRuntime,
354
+ { contextVirtualization: false, conversationHistory: false },
355
+ );
356
+ if (routingSession.supportsCognitiveRoutingRuntime() && typeof pi.registerShortcut === "function") {
357
+ pi.registerShortcut("ctrl+shift+r", {
358
+ description: "Cycle the Cognitive Routing manual standard/reasoning hold",
359
+ handler: async (ctx) => {
360
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
361
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
362
+ return;
363
+ }
364
+ const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedManual();
365
+ if (armedCycle) {
366
+ routingSession.beginExplicitReactivation();
367
+ ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${armedCycle.target}.`, "info");
368
+ await applyLiveCapabilityStateForSession(ctx, {
369
+ reconcileCognitiveRouting: true,
370
+ materializeCognitiveRouting: !isPiFlowHost(pi?.host),
371
+ });
372
+ return;
373
+ }
374
+ if (!routingSession.hasController()) {
375
+ routingSession.beginExplicitReactivation();
376
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
377
+ }
378
+ const state = routingSession.snapshot().runtimeState;
379
+ if (!state) {
380
+ ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
381
+ return;
382
+ }
383
+ const target = state.activeProfile === "reasoning" ? "standard" : "reasoning";
384
+ const result = await routingSession.setManualProfile(target, "profile-shortcut");
385
+ if (result.status === "active") {
386
+ ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${target}.`, "info");
387
+ } else {
388
+ ctx.ui?.notify?.(`Cognitive Routing could not set the manual profile: ${result.reason}.`, "warning");
389
+ }
390
+ await applyLiveCapabilityStateForSession(ctx);
391
+ },
392
+ });
393
+ pi.registerShortcut("ctrl+shift+a", {
394
+ description: "Set Cognitive Routing to automatic Reasoning control",
395
+ handler: async (ctx) => {
396
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
397
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
398
+ return;
399
+ }
400
+ const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedAutomatic();
401
+ if (armedCycle) {
402
+ if (!armedCycle.changed) {
403
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
404
+ return;
405
+ }
406
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
407
+ routingSession.beginExplicitReactivation();
408
+ await applyLiveCapabilityStateForSession(ctx, {
409
+ reconcileCognitiveRouting: true,
410
+ materializeCognitiveRouting: !isPiFlowHost(pi?.host),
411
+ });
412
+ return;
413
+ }
414
+ if (!routingSession.hasController()) {
415
+ routingSession.beginExplicitReactivation();
416
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
417
+ }
418
+ const result = await routingSession.setAutomaticControl("profile-shortcut");
419
+ if (result.status === "automatic") {
420
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
421
+ } else {
422
+ ctx.ui?.notify?.(`Cognitive Routing could not change control: ${result.reason}.`, "warning");
423
+ }
424
+ await applyLiveCapabilityStateForSession(ctx);
425
+ },
426
+ });
427
+ }
428
+ if (!isPiFlowHost(pi?.host) && routingSession.supportsCognitiveRoutingRuntime()) {
429
+ pi.on("model_select", async (event, ctx) => {
430
+ if (!routingSession.hasController()) {
431
+ if (!routingSession.armed) return;
432
+ routingSession.clearArmed();
433
+ routingSession.observeArmedNativeChange(ctx, "Pi model selection");
434
+ await applyLiveCapabilityStateForSession(ctx);
435
+ return;
436
+ }
437
+ const result = await routingSession.observeNativeChange("Pi model selection", event?.source);
438
+ if (result.status !== "ignored") {
439
+ latestCognitiveRoutingContext = ctx;
440
+ providerSurfaceSnapshot = undefined;
441
+ await applyLiveCapabilityStateForSession(ctx);
442
+ }
443
+ });
444
+ pi.on("thinking_level_select", async (_event, ctx) => {
445
+ if (!routingSession.hasController()) {
446
+ if (!routingSession.armed) return;
447
+ routingSession.clearArmed();
448
+ routingSession.observeArmedNativeChange(ctx, "Pi thinking-level selection");
449
+ await applyLiveCapabilityStateForSession(ctx);
450
+ return;
451
+ }
452
+ const result = await routingSession.observeNativeChange("Pi thinking-level selection");
453
+ if (result.status !== "ignored") {
454
+ latestCognitiveRoutingContext = ctx;
455
+ providerSurfaceSnapshot = undefined;
456
+ await applyLiveCapabilityStateForSession(ctx);
457
+ }
458
+ });
459
+ }
142
460
  pi.on("resources_discover", async (event, ctx) => {
143
461
  const cwd = ctx?.cwd ?? event?.cwd ?? process.cwd();
144
- const state = await readCapabilityState(cwd);
462
+ const snapshot =
463
+ providerSurfaceSnapshot?.context === ctx
464
+ ? providerSurfaceSnapshot.value
465
+ : await buildProviderSurface(ctx ?? { cwd }, false);
466
+ const state = snapshot.capabilityState;
145
467
  if (!state.configured) {
146
468
  return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
147
469
  }
148
- if (!state.enabled || !state.skills.effective) {
470
+ if (!state.enabled || !hasUsableMandatoryPrompts(snapshot.freeflowContext)) {
149
471
  return { skillPaths: [] };
150
472
  }
151
- return { skillPaths: freeflowModelSkillPaths() };
473
+ return { skillPaths: freeflowModelSkillPaths(state) };
152
474
  });
153
- pi.on("session_start", async (_event, ctx) => {
154
- restoreModeOverride(ctx);
155
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
156
- readModeState(ctx.cwd),
157
- readOutputRouterConfig(ctx.cwd),
158
- readCapabilityState(ctx.cwd),
159
- ]);
475
+ pi.on("session_start", async (event, ctx) => {
476
+ routingSession.resetForSession(ctx, event);
477
+ latestCognitiveRoutingContext = ctx;
478
+ providerSurfaceSnapshot = undefined;
479
+ runtimeStateRefreshRequired = true;
480
+ restoreSessionOverrides(ctx);
481
+ freeflowContextRuntime = new FreeflowContextRuntime(ctx);
482
+ contextVirtualizationRuntime = new ContextVirtualizationRuntime(pi, ctx, freeflowContextRuntime);
483
+ conversationHistoryRuntime = new ConversationHistoryRuntime(
484
+ ctx,
485
+ (entryId) => contextVirtualizationRuntime?.isSourceFullyProjected(entryId) ?? true,
486
+ freeflowContextRuntime,
487
+ );
488
+ await contextVirtualizationRuntime.recover(ctx);
489
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
160
490
  await refreshRuntimeContext(capabilityState);
161
- setModeStatus(ctx, modeState, capabilityState);
162
- notifyRouterConfigWarnings(ctx, routerConfigResult);
163
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
491
+ routingSession.ensureStartupInactive(ctx, capabilityState.cognitiveRouting?.effective === true);
492
+ routingSession.reconcileNativeEntries(ctx);
493
+ const hasSessionState = sessionHasConversationOrRoutingState(ctx);
494
+ const snapshot = await buildProviderSurface(ctx, hasSessionState);
495
+ if (
496
+ !hasSessionState &&
497
+ snapshot.capabilityState?.cognitiveRouting?.effective === true &&
498
+ routingSession.canAutoActivate()
499
+ ) {
500
+ routingSession.armFromCapability(snapshot.capabilityState.cognitiveRouting);
501
+ } else {
502
+ routingSession.clearArmed();
503
+ }
504
+ registerContextToolForState(snapshot.capabilityState);
505
+ const routingSnapshot = routingSession.snapshot();
506
+ setFreeflowStatus(
507
+ ctx,
508
+ snapshot.capabilityState,
509
+ snapshot.cognitiveRoutingRuntime ?? routingSnapshot.runtimeState,
510
+ snapshot.freeflowContext,
511
+ { startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed },
512
+ );
513
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
514
+ });
515
+ pi.on("agent_settled", async (_event, ctx) => {
516
+ if (!routingSession.hasController()) return undefined;
517
+ await applyLiveCapabilityStateForSession(ctx);
518
+ return undefined;
519
+ });
520
+ pi.on("session_shutdown", async (event) => {
521
+ await routingSession.shutdown(event?.reason);
522
+ providerSurfaceSnapshot = undefined;
523
+ freeflowContextRuntime = undefined;
524
+ contextVirtualizationRuntime = undefined;
525
+ conversationHistoryRuntime = undefined;
164
526
  });
165
527
  pi.on("session_tree", async (_event, ctx) => {
166
- restoreModeOverride(ctx);
167
- await applyLiveCapabilityState(pi, ctx);
528
+ latestCognitiveRoutingContext = ctx;
529
+ providerSurfaceSnapshot = undefined;
530
+ runtimeStateRefreshRequired = true;
531
+ restoreSessionOverrides(ctx);
532
+ await routingSession.reconcileBranch();
533
+ if (contextVirtualizationRuntime) {
534
+ contextVirtualizationRuntime.setContext(ctx);
535
+ await contextVirtualizationRuntime.recover(ctx);
536
+ }
537
+ conversationHistoryRuntime?.setContext(ctx);
538
+ await applyLiveCapabilityStateForSession(ctx);
168
539
  });
169
540
  pi.on("session_compact", async (_event, ctx) => {
170
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
171
- readModeState(ctx.cwd),
172
- readOutputRouterConfig(ctx.cwd),
173
- readCapabilityState(ctx.cwd),
174
- ]);
175
- await refreshRuntimeContext(capabilityState);
176
- setModeStatus(ctx, modeState, capabilityState);
177
- notifyRouterConfigWarnings(ctx, routerConfigResult);
178
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
541
+ latestCognitiveRoutingContext = ctx;
542
+ providerSurfaceSnapshot = undefined;
543
+ runtimeStateRefreshRequired = true;
544
+ await routingSession.reconcileBranch("session-compact");
545
+ if (contextVirtualizationRuntime) {
546
+ contextVirtualizationRuntime.setContext(ctx);
547
+ await contextVirtualizationRuntime.recover(ctx);
548
+ }
549
+ conversationHistoryRuntime?.setContext(ctx);
550
+ await applyLiveCapabilityStateForSession(ctx);
179
551
  });
180
552
  pi.on("before_agent_start", async (event, ctx) => {
181
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
182
- readModeState(ctx.cwd),
183
- readOutputRouterConfig(ctx.cwd),
184
- readCapabilityState(ctx.cwd),
185
- ]);
186
- const freeflowContext = await getRuntimeContext(capabilityState);
187
- setModeStatus(ctx, modeState, capabilityState);
188
- notifyRouterConfigWarnings(ctx, routerConfigResult);
189
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
190
- const freeflowRuntimeContext = runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState);
191
- const workflowMessage = workflowBootstrapMessage(freeflowContext, capabilityState, ctx.sessionManager);
553
+ latestCognitiveRoutingContext = ctx;
554
+ const snapshot = await buildProviderSurface(ctx, true);
555
+ providerSurfaceSnapshot = { context: ctx, value: snapshot };
556
+ registerContextToolForState(snapshot.capabilityState);
557
+ const routingSnapshot = routingSession.snapshot();
558
+ setFreeflowStatus(ctx, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime, snapshot.freeflowContext, {
559
+ startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
560
+ });
561
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
562
+ const freeflowRuntimeContext = runtimeContext(snapshot.freeflowContext, snapshot.capabilityState);
192
563
  const systemPrompt = freeflowRuntimeContext
193
564
  ? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
194
565
  : event.systemPrompt;
195
- return { message: workflowMessage, systemPrompt };
566
+ return { systemPrompt };
196
567
  });
197
568
  pi.on("context", async (event, ctx) => {
198
- const capabilityState = await readCapabilityState(ctx.cwd);
199
- if (capabilityState.skills.effective) {
200
- return undefined;
569
+ const snapshot =
570
+ providerSurfaceSnapshot?.context === ctx ? providerSurfaceSnapshot.value : await buildProviderSurface(ctx, false);
571
+ if (providerSurfaceSnapshot?.context === ctx) providerSurfaceSnapshot = undefined;
572
+ const cognitiveRoutingRuntime = snapshot.cognitiveRoutingRuntime;
573
+ const surfaceCapabilityState = snapshot.capabilityState;
574
+ let changed = false;
575
+ let messages = event.messages
576
+ .map((message) => {
577
+ const filtered = filterBootstrapMessage(message);
578
+ if (filtered !== message) changed = true;
579
+ return filtered;
580
+ })
581
+ .filter((message) => message !== undefined);
582
+ if (contextVirtualizationRuntime) {
583
+ contextVirtualizationRuntime.setContext(ctx);
584
+ const projected = await contextVirtualizationRuntime.project(
585
+ messages,
586
+ surfaceCapabilityState.contextVirtualization?.effective === true,
587
+ );
588
+ if (projected.changed) {
589
+ changed = true;
590
+ messages = projected.messages;
591
+ }
201
592
  }
202
- const messages = event.messages.filter(
203
- (message) => !(message?.role === "custom" && message?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE),
593
+ if (conversationHistoryRuntime && surfaceCapabilityState.conversationHistory?.effective === true) {
594
+ conversationHistoryRuntime.setContext(ctx);
595
+ conversationHistoryRuntime.capture(surfaceCapabilityState.contextVirtualization?.effective === true);
596
+ }
597
+ const forceRuntimeStateRefresh = runtimeStateRefreshRequired;
598
+ const nextMessages = withFreeflowRuntimeState(
599
+ messages,
600
+ surfaceCapabilityState,
601
+ cognitiveRoutingRuntime,
602
+ snapshot.freeflowContext,
603
+ { force: forceRuntimeStateRefresh },
204
604
  );
205
- return messages.length === event.messages.length ? undefined : { messages };
605
+ if (nextMessages !== messages) {
606
+ changed = true;
607
+ messages = nextMessages;
608
+ }
609
+ if (forceRuntimeStateRefresh) runtimeStateRefreshRequired = false;
610
+ return changed ? { messages } : undefined;
206
611
  });
207
612
  pi.on("tool_call", async (event, ctx) => {
208
- const capabilityState = await readCapabilityState(ctx.cwd);
613
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
209
614
  const toolName = typeof event?.toolName === "string" ? event.toolName : "";
210
- if ((!capabilityState.configured || !capabilityState.enabled) && toolName === FREEFLOW_STATUS_TOOL_NAME) {
211
- return disabledToolCall(toolName, "freeflow");
212
- }
213
- if (!capabilityState.outputRouter.enabled && isOutputRouterToolName(toolName)) {
214
- return disabledToolCall(toolName, "output-router");
615
+ if (
616
+ capabilityState.contextVirtualization?.effective !== true &&
617
+ capabilityState.conversationHistory?.effective !== true &&
618
+ toolName === CONTEXT_VIRTUALIZATION_TOOL_NAME
619
+ ) {
620
+ return disabledToolCall(toolName, "context");
215
621
  }
216
622
  return undefined;
217
623
  });
218
624
  pi.on("tool_result", async (event, ctx) => {
219
- const capabilityState = await readCapabilityState(ctx.cwd);
220
- if (!capabilityState.outputRouter.enabled) {
221
- return undefined;
222
- }
223
- const observed = await handleObservedToolRouting(event, ctx);
224
- if (observed) {
225
- return observed;
625
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
626
+ if (routingSession.supportsCognitiveRoutingRuntime() && toolName === COGNITIVE_ROUTING_SWITCH_TOOL_NAME) {
627
+ await applyLiveCapabilityStateForSession(ctx);
226
628
  }
227
- return handleNativeToolSafetyNet(event, ctx);
629
+ return undefined;
228
630
  });
229
631
  for (const { command, skill } of WORKFLOW_COMMANDS) {
230
632
  pi.registerCommand(command, {
@@ -245,25 +647,58 @@ export default function freeflow(pi) {
245
647
  }
246
648
  pi.registerCommand("freeflow", {
247
649
  description: "Open unified Freeflow settings or print compact status",
248
- getArgumentCompletions: freeflowCompletions,
650
+ getArgumentCompletions: (prefix) => freeflowCompletions(prefix, routingSession.supportsCognitiveRoutingRuntime()),
249
651
  handler: async (args, ctx) => {
652
+ const contextInput = (args ?? "").trim();
653
+ if (contextInput === "context" || contextInput.startsWith("context ")) {
654
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
655
+ await handleContextCommand(
656
+ contextInput.slice("context".length).trim(),
657
+ ctx,
658
+ contextVirtualizationRuntime,
659
+ capabilityState.contextVirtualization?.effective === true,
660
+ capabilityState.conversationHistory?.effective === true,
661
+ );
662
+ return;
663
+ }
664
+ if (routingSession.supportsCognitiveRoutingRuntime() && /^profile(?:\s|$)/i.test((args ?? "").trim())) {
665
+ const profileCommandContext = {
666
+ isIdle: ctx?.isIdle,
667
+ ui: ctx?.ui,
668
+ history: (options) => routingSession.history(options) ?? readCognitiveRoutingHistory(ctx, options),
669
+ };
670
+ const historyCommand = /^profile\s+history(?:\s|$)/i.test((args ?? "").trim());
671
+ if (historyCommand) {
672
+ await handleCognitiveRoutingProfileCommand(args, profileCommandContext, routingSession.commandController());
673
+ return;
674
+ }
675
+ if (!routingSession.hasController() && !routingSession.armed) {
676
+ routingSession.beginExplicitReactivation();
677
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
678
+ }
679
+ const profileController = routingSession.commandController();
680
+ if (await handleCognitiveRoutingProfileCommand(args, profileCommandContext, profileController)) {
681
+ if (profileController) {
682
+ routingSession.beginExplicitReactivation();
683
+ await applyLiveCapabilityStateForSession(ctx, {
684
+ reconcileCognitiveRouting: routingSession.armed !== undefined,
685
+ materializeCognitiveRouting: routingSession.armed !== undefined && !isPiFlowHost(pi?.host),
686
+ });
687
+ }
688
+ return;
689
+ }
690
+ }
250
691
  await handleFreeflowCommand(
251
692
  args,
252
693
  ctx,
253
- async () => {
254
- await applyLiveCapabilityState(pi, ctx);
694
+ async (_changed, options = {}) => {
695
+ await applyLiveCapabilityStateForSession(ctx, {
696
+ reconcileCognitiveRouting: options.reconcileCognitiveRouting ?? true,
697
+ });
255
698
  },
256
699
  pi,
700
+ routingSession.commandController(),
257
701
  );
258
702
  },
259
703
  });
260
- pi.registerCommand("output-router", {
261
- description: "Open Freeflow Output Router settings or print compact status",
262
- getArgumentCompletions: capabilityCompletions,
263
- handler: async (args, ctx) => {
264
- await handleOutputRouterCommand(args, ctx, async () => {
265
- await applyLiveCapabilityState(pi, ctx);
266
- });
267
- },
268
- });
269
704
  }