@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,38 +1,176 @@
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 type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+
3
+ import {
4
+ COGNITIVE_ROUTING_CONTROL_ENTRY,
5
+ COGNITIVE_ROUTING_INACTIVE_ENTRY,
6
+ COGNITIVE_ROUTING_INTENT_ENTRY,
7
+ } from "./cognitive-routing/controller.js";
8
+ import { PiRoutingSession, type PiRoutingSessionSnapshot } from "./cognitive-routing/pi-routing-session.js";
9
+ import {
10
+ cognitiveRoutingProfileCompletions,
11
+ handleCognitiveRoutingProfileCommand,
12
+ } from "./cognitive-routing/commands.js";
13
+ import { registerCognitiveRoutingHistoryTool, registerCognitiveRoutingTool } from "./cognitive-routing/tool.js";
14
+ import { readCognitiveRoutingHistory } from "./cognitive-routing/history.js";
15
+ import { ConversationHistoryRuntime } from "./conversation-history/runtime.js";
16
+ import { FreeflowContextRuntime } from "./freeflow-context/runtime.js";
17
+ import { CONTEXT_VIRTUALIZATION_TOOL_NAME, registerFreeflowContextTool } from "./freeflow-context/tool.js";
18
+ import { handleContextCommand } from "./context-virtualization/commands.js";
19
+ import { ContextVirtualizationRuntime } from "./context-virtualization/runtime.js";
20
+ import { handleFreeflowCommand } from "./settings/settings-ui.js";
21
+ import { isPiFlowHost } from "./runtime/runtime-identity.js";
5
22
  import {
6
23
  CONTRIBUTOR_COMMANDS,
24
+ COGNITIVE_ROUTING_SWITCH_TOOL_NAME,
7
25
  WORKFLOW_COMMANDS,
8
- WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
9
- FREEFLOW_STATUS_TOOL_NAME,
10
26
  freeflowModelSkillPaths,
11
27
  freeflowSkillPath,
12
28
  getRuntimeContext,
13
- OUTPUT_ROUTER_TOOL_NAMES,
29
+ hasUsableMandatoryPrompts,
30
+ isPromptAvailable,
14
31
  readCapabilityState,
15
- readModeState,
16
- readOutputRouterConfig,
17
32
  refreshRuntimeContext,
18
- restoreModeOverride,
33
+ restoreSessionOverrides,
19
34
  runtimeContext,
20
- workflowBootstrapMessage,
21
- setModeStatus,
35
+ filterBootstrapMessage,
36
+ setFreeflowStatus,
22
37
  skillPrompt,
23
- notifyRouterConfigWarnings,
38
+ withFreeflowRuntimeState,
24
39
  } from "./runtime/runtime-context.js";
25
40
 
26
- function isOutputRouterToolName(name: string): boolean {
27
- return OUTPUT_ROUTER_TOOL_NAMES.includes(name);
41
+ function unavailableCapability(capability: any, code: string, message: string): any {
42
+ return {
43
+ ...capability,
44
+ effective: false,
45
+ blockingReason: { code, message },
46
+ };
28
47
  }
29
48
 
30
- async function applyCapabilityToolVisibility(pi: any, ctx: any, capabilityState = undefined): Promise<void> {
31
- if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") {
32
- return;
49
+ function modelFacingCapabilityState(
50
+ capabilityState: any,
51
+ freeflowContext: any,
52
+ routingSnapshot: PiRoutingSessionSnapshot,
53
+ cognitiveRoutingActivationFailed = false,
54
+ ): any {
55
+ const surfaceState = {
56
+ ...capabilityState,
57
+ contextVirtualization: { ...capabilityState?.contextVirtualization },
58
+ conversationHistory: { ...capabilityState?.conversationHistory },
59
+ cognitiveRouting: { ...capabilityState?.cognitiveRouting },
60
+ };
61
+ if (surfaceState.enabled !== true) return surfaceState;
62
+
63
+ const markUnavailable = (key: string, message: string) => {
64
+ if (surfaceState[key]?.effective === true) {
65
+ surfaceState[key] = unavailableCapability(surfaceState[key], "unavailable", message);
66
+ }
67
+ };
68
+
69
+ if (!hasUsableMandatoryPrompts(freeflowContext)) {
70
+ for (const key of ["contextVirtualization", "conversationHistory", "cognitiveRouting"]) {
71
+ markUnavailable(key, "Mandatory Freeflow prompt is unavailable.");
72
+ }
73
+ return surfaceState;
33
74
  }
34
75
 
35
- const state = capabilityState ?? (await readCapabilityState(ctx.cwd));
76
+ if (
77
+ surfaceState.contextVirtualization?.effective === true &&
78
+ !isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
79
+ ) {
80
+ markUnavailable("contextVirtualization", "Context Virtualization prompt is unavailable.");
81
+ }
82
+ if (
83
+ surfaceState.conversationHistory?.effective === true &&
84
+ !isPromptAvailable(freeflowContext.conversationHistoryPrompt)
85
+ ) {
86
+ markUnavailable("conversationHistory", "Conversation History prompt is unavailable.");
87
+ }
88
+
89
+ if (surfaceState.cognitiveRouting?.effective === true) {
90
+ const controllerState = routingSnapshot.runtimeState;
91
+ if (routingSnapshot.disposition === "blocked") {
92
+ surfaceState.cognitiveRouting = unavailableCapability(
93
+ surfaceState.cognitiveRouting,
94
+ "runtime_blocked",
95
+ routingSnapshot.reason ?? "Cognitive Routing is blocked because its inactive state could not be persisted.",
96
+ );
97
+ } else if (routingSnapshot.startupSelectionSuppressed || routingSnapshot.disposition === "inactive") {
98
+ surfaceState.cognitiveRouting = unavailableCapability(
99
+ surfaceState.cognitiveRouting,
100
+ "runtime_inactive",
101
+ "Cognitive Routing is inactive because Pi owns the startup model or thinking level.",
102
+ );
103
+ } else if (controllerState?.runtimeStatus === "inactive") {
104
+ surfaceState.cognitiveRouting = unavailableCapability(
105
+ surfaceState.cognitiveRouting,
106
+ "runtime_inactive",
107
+ controllerState.runtimeReason ?? "Cognitive Routing is inactive because Pi owns the current model state.",
108
+ );
109
+ } else if (controllerState?.runtimeStatus === "blocked") {
110
+ surfaceState.cognitiveRouting = unavailableCapability(
111
+ surfaceState.cognitiveRouting,
112
+ "runtime_blocked",
113
+ controllerState.runtimeReason ?? "Cognitive Routing is blocked because its state is not proven.",
114
+ );
115
+ } else if (cognitiveRoutingActivationFailed || controllerState?.effective === false) {
116
+ surfaceState.cognitiveRouting = unavailableCapability(
117
+ surfaceState.cognitiveRouting,
118
+ "unavailable",
119
+ "Cognitive Routing could not activate for this session.",
120
+ );
121
+ } else if (!isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)) {
122
+ markUnavailable("cognitiveRouting", "Cognitive Routing prompt is unavailable.");
123
+ }
124
+ }
125
+
126
+ return surfaceState;
127
+ }
128
+
129
+ type SessionEntriesContext = {
130
+ sessionManager?: {
131
+ getBranch?: () => readonly unknown[];
132
+ getEntries?: () => readonly unknown[];
133
+ };
134
+ };
135
+
136
+ function sessionHasConversationOrRoutingState(ctx: SessionEntriesContext | undefined): boolean {
137
+ try {
138
+ const entries = ctx?.sessionManager?.getBranch?.() ?? ctx?.sessionManager?.getEntries?.() ?? [];
139
+ if (!Array.isArray(entries)) return false;
140
+ return entries.some((entry: unknown) => {
141
+ if (!entry || typeof entry !== "object") return false;
142
+ const record = entry as { type?: unknown; customType?: unknown };
143
+ if (
144
+ typeof record.type === "string" &&
145
+ ["message", "custom_message", "compaction", "branch_summary"].includes(record.type)
146
+ ) {
147
+ return true;
148
+ }
149
+ return (
150
+ record.type === "custom" &&
151
+ (record.customType === COGNITIVE_ROUTING_INTENT_ENTRY ||
152
+ record.customType === COGNITIVE_ROUTING_CONTROL_ENTRY ||
153
+ record.customType === COGNITIVE_ROUTING_INACTIVE_ENTRY)
154
+ );
155
+ });
156
+ } catch {
157
+ return false;
158
+ }
159
+ }
160
+
161
+ async function applyCapabilityToolVisibility(
162
+ pi: any,
163
+ ctx: any,
164
+ capabilityState = undefined,
165
+ routingSnapshot: PiRoutingSessionSnapshot = {
166
+ status: "available",
167
+ disposition: "available",
168
+ startupSelectionSuppressed: false,
169
+ },
170
+ ): Promise<void> {
171
+ if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") return;
172
+
173
+ const state = capabilityState ?? (await readCapabilityState(ctx.cwd, ctx, pi?.host));
36
174
  const allToolNames = pi
37
175
  .getAllTools()
38
176
  .map((tool: any) => tool?.name)
@@ -43,27 +181,27 @@ async function applyCapabilityToolVisibility(pi: any, ctx: any, capabilityState
43
181
  (Array.isArray(currentActive) ? currentActive : allToolNames).filter((name: string) => allToolNameSet.has(name)),
44
182
  );
45
183
 
46
- if (allToolNameSet.has(FREEFLOW_STATUS_TOOL_NAME)) {
47
- if (state.configured && state.enabled) active.add(FREEFLOW_STATUS_TOOL_NAME);
48
- else active.delete(FREEFLOW_STATUS_TOOL_NAME);
184
+ if (allToolNameSet.has(COGNITIVE_ROUTING_SWITCH_TOOL_NAME)) {
185
+ const controllerState = routingSnapshot.runtimeState;
186
+ const routingToolActive =
187
+ state.cognitiveRouting?.effective === true &&
188
+ controllerState?.effective === true &&
189
+ controllerState.controlMode === "automatic";
190
+ if (routingToolActive) active.add(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
191
+ else active.delete(COGNITIVE_ROUTING_SWITCH_TOOL_NAME);
49
192
  }
50
193
 
51
- for (const toolName of OUTPUT_ROUTER_TOOL_NAMES) {
52
- if (!allToolNameSet.has(toolName)) continue;
53
- if (state.outputRouter.enabled) active.add(toolName);
54
- else active.delete(toolName);
194
+ if (allToolNameSet.has(CONTEXT_VIRTUALIZATION_TOOL_NAME)) {
195
+ if (state.contextVirtualization?.effective === true || state.conversationHistory?.effective === true) {
196
+ active.add(CONTEXT_VIRTUALIZATION_TOOL_NAME);
197
+ } else {
198
+ active.delete(CONTEXT_VIRTUALIZATION_TOOL_NAME);
199
+ }
55
200
  }
56
201
 
57
202
  pi.setActiveTools([...active]);
58
203
  }
59
204
 
60
- async function applyLiveCapabilityState(pi: any, ctx: any): Promise<void> {
61
- const [modeState, capabilityState] = await Promise.all([readModeState(ctx.cwd), readCapabilityState(ctx.cwd)]);
62
- await refreshRuntimeContext(capabilityState);
63
- setModeStatus(ctx, modeState, capabilityState);
64
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
65
- }
66
-
67
205
  function disabledToolCall(toolName: string, capability: string) {
68
206
  const command = capability === "freeflow" ? "/freeflow settings" : `/${capability} settings`;
69
207
  return {
@@ -72,17 +210,7 @@ function disabledToolCall(toolName: string, capability: string) {
72
210
  };
73
211
  }
74
212
 
75
- function capabilityCompletions(prefix: string | undefined) {
76
- const query = prefix ?? "";
77
- return [
78
- { value: "settings", label: "settings", description: "Open repository Output Router settings" },
79
- { value: "status", label: "status", description: "Show effective Output Router state" },
80
- { value: "enable", label: "enable", description: "Enable Output Router for this repository" },
81
- { value: "disable", label: "disable", description: "Disable Output Router for this repository" },
82
- ].filter((item) => item.value.startsWith(query));
83
- }
84
-
85
- function freeflowCompletions(prefix: string | undefined) {
213
+ function freeflowCompletions(prefix: string | undefined, cognitiveRoutingAvailable = false) {
86
214
  const query = prefix ?? "";
87
215
  if (query.startsWith("settings ")) {
88
216
  const settingsQuery = query.slice("settings ".length);
@@ -94,25 +222,30 @@ function freeflowCompletions(prefix: string | undefined) {
94
222
  .filter((item) => item.value.startsWith(settingsQuery))
95
223
  .map((item) => ({ ...item, value: `settings ${item.value}` }));
96
224
  }
97
- if (query.startsWith("mode ")) {
98
- const modeQuery = query.slice("mode ".length);
225
+ if (cognitiveRoutingAvailable && query.startsWith("profile ")) {
226
+ return cognitiveRoutingProfileCompletions(query.slice("profile ".length)).map((item) => ({
227
+ ...item,
228
+ value: `profile ${item.value}`,
229
+ }));
230
+ }
231
+ if (query.startsWith("context ")) {
232
+ const contextQuery = query.slice("context ".length);
99
233
  return [
100
- { value: "conversation", label: "conversation", description: "Read-only discussion and inspection" },
101
- { value: "workflow", label: "workflow", description: "Adaptive workflow for consequential work" },
102
- { value: "strict-workflow", label: "strict-workflow", description: "Stronger pressure at high-risk boundaries" },
103
- {
104
- value: "reset",
105
- label: "reset",
106
- description: "Clear the session override and use the configured default",
107
- },
234
+ { value: "status", label: "status", description: "Show Freeflow Context state" },
235
+ { value: "list", label: "list", description: "List archived context projections" },
236
+ { value: "restore", label: "restore", description: "Restore one or more context references" },
237
+ { value: "reset all", label: "reset all", description: "Reset projection decisions on the active branch" },
108
238
  ]
109
- .filter((item) => item.value.startsWith(modeQuery))
110
- .map((item) => ({ ...item, value: `mode ${item.value}` }));
239
+ .filter((item) => item.value.startsWith(contextQuery))
240
+ .map((item) => ({ ...item, value: `context ${item.value}` }));
111
241
  }
112
242
  return [
113
243
  { value: "settings", label: "settings", description: "Open personal override settings" },
114
244
  { value: "status", label: "status", description: "Show effective Freeflow state" },
115
- { value: "mode", label: "mode", description: "Select a temporary session mode" },
245
+ { value: "context", label: "context", description: "Inspect Freeflow Context" },
246
+ ...(cognitiveRoutingAvailable
247
+ ? [{ value: "profile", label: "profile", description: "Hold or release Cognitive Routing profile control" }]
248
+ : []),
116
249
  { value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
117
250
  { value: "disable", label: "disable", description: "Disable Freeflow for this repository" },
118
251
  ].filter((item) => item.value.startsWith(query));
@@ -126,10 +259,17 @@ function bypassCompletions(prefix: string | undefined) {
126
259
  ].filter((item) => item.value.startsWith(query));
127
260
  }
128
261
 
129
- async function sendSkillCommand(pi: any, ctx: any, skill: string, args: string | undefined) {
130
- const state = await readCapabilityState(ctx.cwd);
262
+ type FreeflowExtensionAPI = ExtensionAPI & { host?: unknown };
263
+
264
+ async function sendSkillCommand(
265
+ pi: FreeflowExtensionAPI,
266
+ ctx: ExtensionCommandContext,
267
+ skill: string,
268
+ args: string | undefined,
269
+ ) {
270
+ const state = await readCapabilityState(ctx.cwd, ctx, pi?.host);
131
271
  if (skill === "setup-freeflow" && !state.configured) {
132
- await pi.sendUserMessage(skillPrompt(skill, args));
272
+ await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
133
273
  return;
134
274
  }
135
275
  if (!state.configured) {
@@ -143,110 +283,400 @@ async function sendSkillCommand(pi: any, ctx: any, skill: string, args: string |
143
283
  );
144
284
  return;
145
285
  }
146
- if (!state.skills.effective) {
147
- ctx.ui.notify("Freeflow skills are disabled. Use /freeflow settings to enable skills.", "warning");
286
+ const freeflowContext = await getRuntimeContext(state);
287
+ if (!hasUsableMandatoryPrompts(freeflowContext)) {
288
+ ctx.ui.notify("Freeflow core prompts are unavailable; the requested skill cannot be dispatched.", "warning");
148
289
  return;
149
290
  }
150
- await pi.sendUserMessage(skillPrompt(skill, args));
291
+ await pi.sendUserMessage(skillPrompt(skill, args), { expandPromptTemplates: true });
151
292
  }
152
293
 
153
- export default function freeflow(pi) {
154
- registerRouterTools(pi);
294
+ export default function freeflow(pi: FreeflowExtensionAPI) {
295
+ // SAFETY: These helpers register complete Pi tool definitions but retain legacy structural typing for PiFlow compatibility.
296
+ const toolRegistrar = pi as unknown as { registerTool(tool: Record<string, unknown>): void };
297
+ const routingSession = new PiRoutingSession({ pi, stockPi: !isPiFlowHost(pi?.host) });
298
+ let latestCognitiveRoutingContext: any;
299
+ let providerSurfaceSnapshot: { context: any; value: any } | undefined;
300
+ let runtimeStateRefreshRequired = true;
301
+ let freeflowContextRuntime: FreeflowContextRuntime | undefined;
302
+ let contextVirtualizationRuntime: ContextVirtualizationRuntime | undefined;
303
+ let conversationHistoryRuntime: ConversationHistoryRuntime | undefined;
304
+ const registerContextToolForState = (capabilityState: any) => {
305
+ registerFreeflowContextTool(
306
+ toolRegistrar,
307
+ () => contextVirtualizationRuntime,
308
+ () => conversationHistoryRuntime,
309
+ {
310
+ contextVirtualization: capabilityState?.contextVirtualization?.effective === true,
311
+ conversationHistory: capabilityState?.conversationHistory?.effective === true,
312
+ },
313
+ );
314
+ };
315
+ const buildProviderSurface = async (ctx: any, activateCognitiveRouting = false): Promise<any> => {
316
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
317
+ const freeflowContext = await getRuntimeContext(capabilityState);
318
+ const promptCapabilityState = modelFacingCapabilityState(
319
+ capabilityState,
320
+ freeflowContext,
321
+ routingSession.snapshot(),
322
+ );
323
+ let activationAttempted = false;
324
+ if (
325
+ activateCognitiveRouting &&
326
+ routingSession.canAutoActivate() &&
327
+ (!routingSession.hasController() || promptCapabilityState.cognitiveRouting?.effective !== true)
328
+ ) {
329
+ activationAttempted = promptCapabilityState.cognitiveRouting?.effective === true;
330
+ try {
331
+ await routingSession.reconcileController(
332
+ ctx,
333
+ promptCapabilityState,
334
+ routingSession.armed ? { ...routingSession.armed } : undefined,
335
+ );
336
+ if (routingSession.hasController()) {
337
+ routingSession.clearArmed();
338
+ if (routingSession.snapshot().status === "active") routingSession.markActive();
339
+ }
340
+ } catch {
341
+ routingSession.clearController();
342
+ }
343
+ }
344
+ const surfaceCapabilityState = modelFacingCapabilityState(
345
+ promptCapabilityState,
346
+ freeflowContext,
347
+ routingSession.snapshot(),
348
+ activationAttempted && !routingSession.hasController(),
349
+ );
350
+ const routingSnapshot = routingSession.snapshot();
351
+ return {
352
+ capabilityState: surfaceCapabilityState,
353
+ freeflowContext,
354
+ cognitiveRoutingRuntime: routingSnapshot.runtimeState,
355
+ configuredCapabilityState: capabilityState,
356
+ };
357
+ };
358
+ const applyLiveCapabilityStateForSession = async (
359
+ ctx: any,
360
+ options: { reconcileCognitiveRouting?: boolean; materializeCognitiveRouting?: boolean } = {},
361
+ ): Promise<void> => {
362
+ providerSurfaceSnapshot = undefined;
363
+ await routingSession.applyLiveCapabilityState(ctx, options);
364
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
365
+ const freeflowContext = await getRuntimeContext(capabilityState);
366
+ const surfaceCapabilityState = modelFacingCapabilityState(
367
+ capabilityState,
368
+ freeflowContext,
369
+ routingSession.snapshot(),
370
+ );
371
+ const routingSnapshot = routingSession.snapshot();
372
+ setFreeflowStatus(ctx, surfaceCapabilityState, routingSnapshot.runtimeState, freeflowContext, {
373
+ startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
374
+ });
375
+ await applyCapabilityToolVisibility(pi, ctx, surfaceCapabilityState, routingSnapshot);
376
+ registerContextToolForState(surfaceCapabilityState);
377
+ };
378
+
379
+ if (routingSession.supportsCognitiveRoutingRuntime()) {
380
+ registerCognitiveRoutingTool(toolRegistrar, () => routingSession.controllerForTool());
381
+ registerCognitiveRoutingHistoryTool(toolRegistrar, (options, context) => {
382
+ return (
383
+ routingSession.history(options) ??
384
+ readCognitiveRoutingHistory(context ?? latestCognitiveRoutingContext, options)
385
+ );
386
+ });
387
+ }
388
+ registerFreeflowContextTool(
389
+ toolRegistrar,
390
+ () => contextVirtualizationRuntime,
391
+ () => conversationHistoryRuntime,
392
+ { contextVirtualization: false, conversationHistory: false },
393
+ );
394
+
395
+ if (routingSession.supportsCognitiveRoutingRuntime() && typeof pi.registerShortcut === "function") {
396
+ pi.registerShortcut("ctrl+shift+r", {
397
+ description: "Cycle the Cognitive Routing manual standard/reasoning hold",
398
+ handler: async (ctx) => {
399
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
400
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
401
+ return;
402
+ }
403
+ const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedManual();
404
+ if (armedCycle) {
405
+ routingSession.beginExplicitReactivation();
406
+ ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${armedCycle.target}.`, "info");
407
+ await applyLiveCapabilityStateForSession(ctx, {
408
+ reconcileCognitiveRouting: true,
409
+ materializeCognitiveRouting: !isPiFlowHost(pi?.host),
410
+ });
411
+ return;
412
+ }
413
+ if (!routingSession.hasController()) {
414
+ routingSession.beginExplicitReactivation();
415
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
416
+ }
417
+ const state = routingSession.snapshot().runtimeState;
418
+ if (!state) {
419
+ ctx.ui?.notify?.("Cognitive Routing is unavailable for this session.", "warning");
420
+ return;
421
+ }
422
+ const target = state.activeProfile === "reasoning" ? "standard" : "reasoning";
423
+ const result = await routingSession.setManualProfile(target, "profile-shortcut");
424
+ if (result.status === "active") {
425
+ ctx.ui?.notify?.(`Cognitive Routing manual hold set to ${target}.`, "info");
426
+ } else {
427
+ ctx.ui?.notify?.(`Cognitive Routing could not set the manual profile: ${result.reason}.`, "warning");
428
+ }
429
+ await applyLiveCapabilityStateForSession(ctx);
430
+ },
431
+ });
432
+ pi.registerShortcut("ctrl+shift+a", {
433
+ description: "Set Cognitive Routing to automatic Reasoning control",
434
+ handler: async (ctx) => {
435
+ if (typeof ctx?.isIdle === "function" && !ctx.isIdle()) {
436
+ ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
437
+ return;
438
+ }
439
+ const armedCycle = routingSession.hasController() ? undefined : routingSession.cycleArmedAutomatic();
440
+ if (armedCycle) {
441
+ if (!armedCycle.changed) {
442
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
443
+ return;
444
+ }
445
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
446
+ routingSession.beginExplicitReactivation();
447
+ await applyLiveCapabilityStateForSession(ctx, {
448
+ reconcileCognitiveRouting: true,
449
+ materializeCognitiveRouting: !isPiFlowHost(pi?.host),
450
+ });
451
+ return;
452
+ }
453
+ if (!routingSession.hasController()) {
454
+ routingSession.beginExplicitReactivation();
455
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
456
+ }
457
+ const result = await routingSession.setAutomaticControl("profile-shortcut");
458
+ if (result.status === "automatic") {
459
+ ctx.ui?.notify?.("Cognitive Routing automatic control active.", "info");
460
+ } else {
461
+ ctx.ui?.notify?.(`Cognitive Routing could not change control: ${result.reason}.`, "warning");
462
+ }
463
+ await applyLiveCapabilityStateForSession(ctx);
464
+ },
465
+ });
466
+ }
467
+
468
+ if (!isPiFlowHost(pi?.host) && routingSession.supportsCognitiveRoutingRuntime()) {
469
+ pi.on("model_select", async (event, ctx) => {
470
+ if (!routingSession.hasController()) {
471
+ if (!routingSession.armed) return;
472
+ routingSession.clearArmed();
473
+ routingSession.observeArmedNativeChange(ctx, "Pi model selection");
474
+ await applyLiveCapabilityStateForSession(ctx);
475
+ return;
476
+ }
477
+ const result = await routingSession.observeNativeChange("Pi model selection", event?.source);
478
+ if (result.status !== "ignored") {
479
+ latestCognitiveRoutingContext = ctx;
480
+ providerSurfaceSnapshot = undefined;
481
+ await applyLiveCapabilityStateForSession(ctx);
482
+ }
483
+ });
484
+ pi.on("thinking_level_select", async (_event, ctx) => {
485
+ if (!routingSession.hasController()) {
486
+ if (!routingSession.armed) return;
487
+ routingSession.clearArmed();
488
+ routingSession.observeArmedNativeChange(ctx, "Pi thinking-level selection");
489
+ await applyLiveCapabilityStateForSession(ctx);
490
+ return;
491
+ }
492
+ const result = await routingSession.observeNativeChange("Pi thinking-level selection");
493
+ if (result.status !== "ignored") {
494
+ latestCognitiveRoutingContext = ctx;
495
+ providerSurfaceSnapshot = undefined;
496
+ await applyLiveCapabilityStateForSession(ctx);
497
+ }
498
+ });
499
+ }
155
500
 
156
501
  pi.on("resources_discover", async (event, ctx) => {
157
502
  const cwd = ctx?.cwd ?? event?.cwd ?? process.cwd();
158
- const state = await readCapabilityState(cwd);
503
+ const snapshot =
504
+ providerSurfaceSnapshot?.context === ctx
505
+ ? providerSurfaceSnapshot.value
506
+ : await buildProviderSurface(ctx ?? { cwd }, false);
507
+ const state = snapshot.capabilityState;
159
508
  if (!state.configured) {
160
509
  return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
161
510
  }
162
- if (!state.enabled || !state.skills.effective) {
511
+ if (!state.enabled || !hasUsableMandatoryPrompts(snapshot.freeflowContext)) {
163
512
  return { skillPaths: [] };
164
513
  }
165
- return { skillPaths: freeflowModelSkillPaths() };
514
+ return { skillPaths: freeflowModelSkillPaths(state) };
166
515
  });
167
516
 
168
- pi.on("session_start", async (_event, ctx) => {
169
- restoreModeOverride(ctx);
170
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
171
- readModeState(ctx.cwd),
172
- readOutputRouterConfig(ctx.cwd),
173
- readCapabilityState(ctx.cwd),
174
- ]);
517
+ pi.on("session_start", async (event, ctx) => {
518
+ routingSession.resetForSession(ctx, event);
519
+ latestCognitiveRoutingContext = ctx;
520
+ providerSurfaceSnapshot = undefined;
521
+ runtimeStateRefreshRequired = true;
522
+ restoreSessionOverrides(ctx);
523
+ freeflowContextRuntime = new FreeflowContextRuntime(ctx);
524
+ contextVirtualizationRuntime = new ContextVirtualizationRuntime(pi, ctx, freeflowContextRuntime);
525
+ conversationHistoryRuntime = new ConversationHistoryRuntime(
526
+ ctx,
527
+ (entryId) => contextVirtualizationRuntime?.isSourceFullyProjected(entryId) ?? true,
528
+ freeflowContextRuntime,
529
+ );
530
+ await contextVirtualizationRuntime.recover(ctx);
531
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
175
532
  await refreshRuntimeContext(capabilityState);
176
- setModeStatus(ctx, modeState, capabilityState);
177
- notifyRouterConfigWarnings(ctx, routerConfigResult);
178
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
533
+ routingSession.ensureStartupInactive(ctx, capabilityState.cognitiveRouting?.effective === true);
534
+ routingSession.reconcileNativeEntries(ctx);
535
+ const hasSessionState = sessionHasConversationOrRoutingState(ctx);
536
+ const snapshot = await buildProviderSurface(ctx, hasSessionState);
537
+ if (
538
+ !hasSessionState &&
539
+ snapshot.capabilityState?.cognitiveRouting?.effective === true &&
540
+ routingSession.canAutoActivate()
541
+ ) {
542
+ routingSession.armFromCapability(snapshot.capabilityState.cognitiveRouting);
543
+ } else {
544
+ routingSession.clearArmed();
545
+ }
546
+ registerContextToolForState(snapshot.capabilityState);
547
+ const routingSnapshot = routingSession.snapshot();
548
+ setFreeflowStatus(
549
+ ctx,
550
+ snapshot.capabilityState,
551
+ snapshot.cognitiveRoutingRuntime ?? routingSnapshot.runtimeState,
552
+ snapshot.freeflowContext,
553
+ { startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed },
554
+ );
555
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
556
+ });
557
+
558
+ pi.on("agent_settled", async (_event, ctx) => {
559
+ if (!routingSession.hasController()) return undefined;
560
+ await applyLiveCapabilityStateForSession(ctx);
561
+ return undefined;
562
+ });
563
+
564
+ pi.on("session_shutdown", async (event) => {
565
+ await routingSession.shutdown(event?.reason);
566
+ providerSurfaceSnapshot = undefined;
567
+ freeflowContextRuntime = undefined;
568
+ contextVirtualizationRuntime = undefined;
569
+ conversationHistoryRuntime = undefined;
179
570
  });
180
571
 
181
572
  pi.on("session_tree", async (_event, ctx) => {
182
- restoreModeOverride(ctx);
183
- await applyLiveCapabilityState(pi, ctx);
573
+ latestCognitiveRoutingContext = ctx;
574
+ providerSurfaceSnapshot = undefined;
575
+ runtimeStateRefreshRequired = true;
576
+ restoreSessionOverrides(ctx);
577
+ await routingSession.reconcileBranch();
578
+ if (contextVirtualizationRuntime) {
579
+ contextVirtualizationRuntime.setContext(ctx);
580
+ await contextVirtualizationRuntime.recover(ctx);
581
+ }
582
+ conversationHistoryRuntime?.setContext(ctx);
583
+ await applyLiveCapabilityStateForSession(ctx);
184
584
  });
185
585
 
186
586
  pi.on("session_compact", async (_event, ctx) => {
187
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
188
- readModeState(ctx.cwd),
189
- readOutputRouterConfig(ctx.cwd),
190
- readCapabilityState(ctx.cwd),
191
- ]);
192
- await refreshRuntimeContext(capabilityState);
193
- setModeStatus(ctx, modeState, capabilityState);
194
- notifyRouterConfigWarnings(ctx, routerConfigResult);
195
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
587
+ latestCognitiveRoutingContext = ctx;
588
+ providerSurfaceSnapshot = undefined;
589
+ runtimeStateRefreshRequired = true;
590
+ await routingSession.reconcileBranch("session-compact");
591
+ if (contextVirtualizationRuntime) {
592
+ contextVirtualizationRuntime.setContext(ctx);
593
+ await contextVirtualizationRuntime.recover(ctx);
594
+ }
595
+ conversationHistoryRuntime?.setContext(ctx);
596
+ await applyLiveCapabilityStateForSession(ctx);
196
597
  });
197
598
 
198
599
  pi.on("before_agent_start", async (event, ctx) => {
199
- const [modeState, routerConfigResult, capabilityState] = await Promise.all([
200
- readModeState(ctx.cwd),
201
- readOutputRouterConfig(ctx.cwd),
202
- readCapabilityState(ctx.cwd),
203
- ]);
204
- const freeflowContext = await getRuntimeContext(capabilityState);
205
- setModeStatus(ctx, modeState, capabilityState);
206
- notifyRouterConfigWarnings(ctx, routerConfigResult);
207
- await applyCapabilityToolVisibility(pi, ctx, capabilityState);
208
- const freeflowRuntimeContext = runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState);
209
- const workflowMessage = workflowBootstrapMessage(freeflowContext, capabilityState, ctx.sessionManager);
600
+ latestCognitiveRoutingContext = ctx;
601
+ const snapshot = await buildProviderSurface(ctx, true);
602
+ providerSurfaceSnapshot = { context: ctx, value: snapshot };
603
+ registerContextToolForState(snapshot.capabilityState);
604
+ const routingSnapshot = routingSession.snapshot();
605
+ setFreeflowStatus(ctx, snapshot.capabilityState, snapshot.cognitiveRoutingRuntime, snapshot.freeflowContext, {
606
+ startupSelectionSuppressed: routingSnapshot.startupSelectionSuppressed,
607
+ });
608
+ await applyCapabilityToolVisibility(pi, ctx, snapshot.capabilityState, routingSnapshot);
609
+ const freeflowRuntimeContext = runtimeContext(snapshot.freeflowContext, snapshot.capabilityState);
210
610
  const systemPrompt = freeflowRuntimeContext
211
611
  ? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
212
612
  : event.systemPrompt;
213
- return { message: workflowMessage, systemPrompt };
613
+ return { systemPrompt };
214
614
  });
215
615
 
216
616
  pi.on("context", async (event, ctx) => {
217
- const capabilityState = await readCapabilityState(ctx.cwd);
218
- if (capabilityState.skills.effective) {
219
- return undefined;
617
+ const snapshot =
618
+ providerSurfaceSnapshot?.context === ctx ? providerSurfaceSnapshot.value : await buildProviderSurface(ctx, false);
619
+ if (providerSurfaceSnapshot?.context === ctx) providerSurfaceSnapshot = undefined;
620
+ const cognitiveRoutingRuntime = snapshot.cognitiveRoutingRuntime;
621
+ const surfaceCapabilityState = snapshot.capabilityState;
622
+ let changed = false;
623
+ let messages = event.messages
624
+ .map((message) => {
625
+ const filtered = filterBootstrapMessage(message);
626
+ if (filtered !== message) changed = true;
627
+ return filtered;
628
+ })
629
+ .filter((message) => message !== undefined);
630
+ if (contextVirtualizationRuntime) {
631
+ contextVirtualizationRuntime.setContext(ctx);
632
+ const projected = await contextVirtualizationRuntime.project(
633
+ messages,
634
+ surfaceCapabilityState.contextVirtualization?.effective === true,
635
+ );
636
+ if (projected.changed) {
637
+ changed = true;
638
+ messages = projected.messages;
639
+ }
220
640
  }
221
-
222
- const messages = event.messages.filter(
223
- (message) => !(message?.role === "custom" && message?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE),
641
+ if (conversationHistoryRuntime && surfaceCapabilityState.conversationHistory?.effective === true) {
642
+ conversationHistoryRuntime.setContext(ctx);
643
+ conversationHistoryRuntime.capture(surfaceCapabilityState.contextVirtualization?.effective === true);
644
+ }
645
+ const forceRuntimeStateRefresh = runtimeStateRefreshRequired;
646
+ const nextMessages = withFreeflowRuntimeState(
647
+ messages,
648
+ surfaceCapabilityState,
649
+ cognitiveRoutingRuntime,
650
+ snapshot.freeflowContext,
651
+ { force: forceRuntimeStateRefresh },
224
652
  );
225
- return messages.length === event.messages.length ? undefined : { messages };
653
+ if (nextMessages !== messages) {
654
+ changed = true;
655
+ messages = nextMessages;
656
+ }
657
+ if (forceRuntimeStateRefresh) runtimeStateRefreshRequired = false;
658
+ return changed ? { messages } : undefined;
226
659
  });
227
660
 
228
661
  pi.on("tool_call", async (event, ctx) => {
229
- const capabilityState = await readCapabilityState(ctx.cwd);
662
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
230
663
  const toolName = typeof event?.toolName === "string" ? event.toolName : "";
231
- if ((!capabilityState.configured || !capabilityState.enabled) && toolName === FREEFLOW_STATUS_TOOL_NAME) {
232
- return disabledToolCall(toolName, "freeflow");
233
- }
234
- if (!capabilityState.outputRouter.enabled && isOutputRouterToolName(toolName)) {
235
- return disabledToolCall(toolName, "output-router");
664
+ if (
665
+ capabilityState.contextVirtualization?.effective !== true &&
666
+ capabilityState.conversationHistory?.effective !== true &&
667
+ toolName === CONTEXT_VIRTUALIZATION_TOOL_NAME
668
+ ) {
669
+ return disabledToolCall(toolName, "context");
236
670
  }
237
671
  return undefined;
238
672
  });
239
673
 
240
674
  pi.on("tool_result", async (event, ctx) => {
241
- const capabilityState = await readCapabilityState(ctx.cwd);
242
- if (!capabilityState.outputRouter.enabled) {
243
- return undefined;
244
- }
245
- const observed = await handleObservedToolRouting(event, ctx);
246
- if (observed) {
247
- return observed;
675
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
676
+ if (routingSession.supportsCognitiveRoutingRuntime() && toolName === COGNITIVE_ROUTING_SWITCH_TOOL_NAME) {
677
+ await applyLiveCapabilityStateForSession(ctx);
248
678
  }
249
- return handleNativeToolSafetyNet(event, ctx);
679
+ return undefined;
250
680
  });
251
681
 
252
682
  for (const { command, skill } of WORKFLOW_COMMANDS) {
@@ -270,26 +700,58 @@ export default function freeflow(pi) {
270
700
 
271
701
  pi.registerCommand("freeflow", {
272
702
  description: "Open unified Freeflow settings or print compact status",
273
- getArgumentCompletions: freeflowCompletions,
703
+ getArgumentCompletions: (prefix) => freeflowCompletions(prefix, routingSession.supportsCognitiveRoutingRuntime()),
274
704
  handler: async (args, ctx) => {
705
+ const contextInput = (args ?? "").trim();
706
+ if (contextInput === "context" || contextInput.startsWith("context ")) {
707
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
708
+ await handleContextCommand(
709
+ contextInput.slice("context".length).trim(),
710
+ ctx,
711
+ contextVirtualizationRuntime,
712
+ capabilityState.contextVirtualization?.effective === true,
713
+ capabilityState.conversationHistory?.effective === true,
714
+ );
715
+ return;
716
+ }
717
+ if (routingSession.supportsCognitiveRoutingRuntime() && /^profile(?:\s|$)/i.test((args ?? "").trim())) {
718
+ const profileCommandContext = {
719
+ isIdle: ctx?.isIdle,
720
+ ui: ctx?.ui,
721
+ history: (options) => routingSession.history(options) ?? readCognitiveRoutingHistory(ctx, options),
722
+ };
723
+ const historyCommand = /^profile\s+history(?:\s|$)/i.test((args ?? "").trim());
724
+ if (historyCommand) {
725
+ await handleCognitiveRoutingProfileCommand(args, profileCommandContext, routingSession.commandController());
726
+ return;
727
+ }
728
+ if (!routingSession.hasController() && !routingSession.armed) {
729
+ routingSession.beginExplicitReactivation();
730
+ await applyLiveCapabilityStateForSession(ctx, { reconcileCognitiveRouting: true });
731
+ }
732
+ const profileController = routingSession.commandController();
733
+ if (await handleCognitiveRoutingProfileCommand(args, profileCommandContext, profileController)) {
734
+ if (profileController) {
735
+ routingSession.beginExplicitReactivation();
736
+ await applyLiveCapabilityStateForSession(ctx, {
737
+ reconcileCognitiveRouting: routingSession.armed !== undefined,
738
+ materializeCognitiveRouting: routingSession.armed !== undefined && !isPiFlowHost(pi?.host),
739
+ });
740
+ }
741
+ return;
742
+ }
743
+ }
275
744
  await handleFreeflowCommand(
276
745
  args,
277
746
  ctx,
278
- async () => {
279
- await applyLiveCapabilityState(pi, ctx);
747
+ async (_changed, options = {}) => {
748
+ await applyLiveCapabilityStateForSession(ctx, {
749
+ reconcileCognitiveRouting: options.reconcileCognitiveRouting ?? true,
750
+ });
280
751
  },
281
752
  pi,
753
+ routingSession.commandController(),
282
754
  );
283
755
  },
284
756
  });
285
-
286
- pi.registerCommand("output-router", {
287
- description: "Open Freeflow Output Router settings or print compact status",
288
- getArgumentCompletions: capabilityCompletions,
289
- handler: async (args, ctx) => {
290
- await handleOutputRouterCommand(args, ctx, async () => {
291
- await applyLiveCapabilityState(pi, ctx);
292
- });
293
- },
294
- });
295
757
  }