@hassangameryt/freeflow 0.5.0 → 0.6.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 (284) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +148 -154
  5. package/capabilities/cognitive-routing/SKILL.md +229 -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 -13
  9. package/hooks/freeflow-runtime-context.mjs +35 -91
  10. package/hooks/tests/check-runtime-context-hook.sh +56 -39
  11. package/package.json +24 -16
  12. package/pi-extension/dist/cognitive-routing/commands.js +96 -0
  13. package/pi-extension/dist/cognitive-routing/config.js +236 -0
  14. package/pi-extension/dist/cognitive-routing/controller.js +862 -0
  15. package/pi-extension/dist/cognitive-routing/history.js +439 -0
  16. package/pi-extension/dist/cognitive-routing/host.js +126 -0
  17. package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
  18. package/pi-extension/dist/cognitive-routing/tool.js +211 -0
  19. package/pi-extension/dist/cognitive-routing/types.js +6 -0
  20. package/pi-extension/dist/context-virtualization/commands.js +89 -0
  21. package/pi-extension/dist/context-virtualization/projector.js +42 -0
  22. package/pi-extension/dist/context-virtualization/runtime.js +356 -0
  23. package/pi-extension/dist/context-virtualization/state.js +57 -0
  24. package/pi-extension/dist/context-virtualization/types.js +10 -0
  25. package/pi-extension/dist/conversation-history/passages.js +66 -0
  26. package/pi-extension/dist/conversation-history/ranking.js +105 -0
  27. package/pi-extension/dist/conversation-history/runtime.js +226 -0
  28. package/pi-extension/dist/conversation-history/search.js +56 -0
  29. package/pi-extension/dist/conversation-history/types.js +1 -0
  30. package/pi-extension/dist/freeflow-context/resolver.js +120 -0
  31. package/pi-extension/dist/freeflow-context/runtime.js +80 -0
  32. package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
  33. package/pi-extension/dist/freeflow-context/tool.js +308 -0
  34. package/pi-extension/dist/freeflow-context/types.js +12 -0
  35. package/pi-extension/dist/freeflow-context/visibility.js +28 -0
  36. package/pi-extension/dist/index.js +516 -98
  37. package/pi-extension/dist/runtime/runtime-context.js +318 -271
  38. package/pi-extension/dist/runtime/runtime-identity.js +5 -0
  39. package/pi-extension/dist/settings/settings-tui.js +78 -0
  40. package/pi-extension/dist/settings/settings-ui.js +593 -563
  41. package/pi-extension/dist/ui/text-component.js +57 -0
  42. package/pi-extension/src/cognitive-routing/commands.ts +119 -0
  43. package/pi-extension/src/cognitive-routing/config.ts +307 -0
  44. package/pi-extension/src/cognitive-routing/controller.ts +1118 -0
  45. package/pi-extension/src/cognitive-routing/history.ts +638 -0
  46. package/pi-extension/src/cognitive-routing/host.ts +172 -0
  47. package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
  48. package/pi-extension/src/cognitive-routing/tool.ts +272 -0
  49. package/pi-extension/src/cognitive-routing/types.ts +89 -0
  50. package/pi-extension/src/context-virtualization/commands.ts +111 -0
  51. package/pi-extension/src/context-virtualization/projector.ts +62 -0
  52. package/pi-extension/src/context-virtualization/runtime.ts +406 -0
  53. package/pi-extension/src/context-virtualization/state.ts +79 -0
  54. package/pi-extension/src/context-virtualization/types.ts +92 -0
  55. package/pi-extension/src/conversation-history/passages.ts +81 -0
  56. package/pi-extension/src/conversation-history/ranking.ts +155 -0
  57. package/pi-extension/src/conversation-history/runtime.ts +250 -0
  58. package/pi-extension/src/conversation-history/search.ts +79 -0
  59. package/pi-extension/src/conversation-history/types.ts +31 -0
  60. package/pi-extension/src/freeflow-context/resolver.ts +139 -0
  61. package/pi-extension/src/freeflow-context/runtime.ts +100 -0
  62. package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
  63. package/pi-extension/src/freeflow-context/tool.ts +360 -0
  64. package/pi-extension/src/freeflow-context/types.ts +70 -0
  65. package/pi-extension/src/freeflow-context/visibility.ts +53 -0
  66. package/pi-extension/src/index.ts +553 -101
  67. package/pi-extension/src/runtime/runtime-context.ts +339 -281
  68. package/pi-extension/src/runtime/runtime-identity.ts +8 -0
  69. package/pi-extension/src/settings/settings-tui.ts +93 -0
  70. package/pi-extension/src/settings/settings-ui.ts +700 -613
  71. package/pi-extension/src/ui/text-component.ts +66 -0
  72. package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
  73. package/pi-extension/tests/cognitive-routing/controller.test.js +1099 -0
  74. package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1071 -0
  75. package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
  76. package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
  77. package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
  78. package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +236 -0
  79. package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
  80. package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
  81. package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
  82. package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
  83. package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
  84. package/pi-extension/tests/conversation-history/search.test.js +97 -0
  85. package/pi-extension/tests/integration/pi-extension.test.js +927 -2048
  86. package/pi-extension/tests/integration/prompt-architecture.test.js +305 -0
  87. package/runtime/prompts/cognitive-routing.md +9 -0
  88. package/runtime/prompts/context-virtualization.md +3 -0
  89. package/runtime/prompts/conversation-history.md +3 -0
  90. package/runtime/prompts/core.md +13 -0
  91. package/runtime/prompts/interaction-contract.md +7 -0
  92. package/runtime/prompts/skills.md +65 -0
  93. package/skills/action-selection/SKILL.md +91 -0
  94. package/skills/bypass/SKILL.md +3 -2
  95. package/skills/commit-work/SKILL.md +1 -1
  96. package/skills/commit-work/references/staging-decisions.md +1 -1
  97. package/skills/decision-gate/SKILL.md +1 -1
  98. package/skills/design-for-depth/SKILL.md +14 -33
  99. package/skills/design-for-depth/references/design-pressure-signals.md +1 -1
  100. package/skills/design-for-depth/references/interface-design-loop.md +1 -1
  101. package/skills/design-for-depth/references/software-design-philosophy.md +1 -1
  102. package/skills/diagnose-failure/SKILL.md +20 -14
  103. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +1 -3
  104. package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +1 -1
  105. package/skills/discuss/SKILL.md +34 -22
  106. package/skills/discuss/references/discussion-continuity.md +71 -0
  107. package/skills/evaluate-skill/SKILL.md +5 -5
  108. package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +42 -2
  109. package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
  110. package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
  111. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
  112. package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
  113. package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
  114. package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
  115. package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
  116. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
  117. package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
  118. package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
  119. package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
  120. package/skills/execute-work/SKILL.md +18 -15
  121. package/skills/execute-work/references/code-practices.md +1 -1
  122. package/skills/execute-work/references/execute-work-edges.md +42 -0
  123. package/skills/finish-branch/SKILL.md +2 -2
  124. package/skills/finish-branch/references/integration-options.md +1 -1
  125. package/skills/handoff/SKILL.md +3 -3
  126. package/skills/launch-work/SKILL.md +1 -1
  127. package/skills/launch-work/references/launch-readiness.md +2 -2
  128. package/skills/migration-work/SKILL.md +2 -2
  129. package/skills/migration-work/references/migration-lifecycle.md +1 -1
  130. package/skills/mode-contract/SKILL.md +4 -4
  131. package/skills/release-work/SKILL.md +1 -1
  132. package/skills/release-work/references/release-evidence.md +1 -1
  133. package/skills/review-artifact/SKILL.md +28 -26
  134. package/skills/review-work/SKILL.md +28 -26
  135. package/skills/review-work/references/{reviewer-prompt.md → independent-work-reviewer-contract.md} +1 -1
  136. package/skills/review-work/references/security-risk-lens.md +1 -1
  137. package/skills/setup-freeflow/SKILL.md +3 -1
  138. package/skills/setup-freeflow/references/activation-contract.md +2 -2
  139. package/skills/setup-freeflow/references/host-setup.md +2 -2
  140. package/skills/simplify-code/SKILL.md +1 -1
  141. package/skills/simplify-code/references/simplification-patterns.md +1 -1
  142. package/skills/tdd/SKILL.md +18 -38
  143. package/skills/tdd/references/test-design.md +2 -2
  144. package/skills/track-work/SKILL.md +362 -58
  145. package/skills/track-work/scripts/lib/codec.mjs +570 -0
  146. package/skills/track-work/scripts/lib/commands.mjs +568 -0
  147. package/skills/track-work/scripts/lib/contract.mjs +303 -0
  148. package/skills/track-work/scripts/lib/model.mjs +506 -0
  149. package/skills/track-work/scripts/lib/operations.mjs +965 -0
  150. package/skills/track-work/scripts/lib/record-store.mjs +264 -0
  151. package/skills/track-work/scripts/lib/result.mjs +37 -0
  152. package/skills/track-work/scripts/lib/rewrites.mjs +740 -0
  153. package/skills/track-work/scripts/lib/schema.mjs +277 -0
  154. package/skills/track-work/scripts/lib/source-inventory.mjs +162 -0
  155. package/skills/track-work/scripts/lib/views.mjs +443 -0
  156. package/skills/track-work/scripts/lib/workspace.mjs +134 -0
  157. package/skills/track-work/scripts/working-record.mjs +122 -0
  158. package/skills/verify-work/SKILL.md +14 -2
  159. package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
  160. package/skills/verify-work/references/integration-evidence.md +1 -1
  161. package/skills/verify-work/references/performance-evidence.md +1 -1
  162. package/skills/workflow/SKILL.md +105 -53
  163. package/skills/workflow/references/domain-skill-composition.md +22 -42
  164. package/skills/write-plan/SKILL.md +1 -1
  165. package/skills/write-skill/SKILL.md +3 -2
  166. package/skills/write-skill/references/progressive-disclosure.md +17 -3
  167. package/capabilities/output-router/SKILL.md +0 -206
  168. package/capabilities/output-router/references/safety-policy.md +0 -40
  169. package/capabilities/output-router/references/setup.md +0 -110
  170. package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
  171. package/pi-extension/dist/output-router/native-safety-net.js +0 -216
  172. package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
  173. package/pi-extension/dist/output-router/renderers.js +0 -1023
  174. package/pi-extension/dist/output-router/router-tools.js +0 -554
  175. package/pi-extension/dist/output-router/schemas.js +0 -383
  176. package/pi-extension/dist/output-router/status.js +0 -744
  177. package/pi-extension/dist/output-router/utils.js +0 -502
  178. package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
  179. package/pi-extension/src/output-router/native-safety-net.ts +0 -248
  180. package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
  181. package/pi-extension/src/output-router/renderers.ts +0 -1108
  182. package/pi-extension/src/output-router/router-tools.ts +0 -579
  183. package/pi-extension/src/output-router/schemas.ts +0 -387
  184. package/pi-extension/src/output-router/status.ts +0 -791
  185. package/pi-extension/src/output-router/utils.ts +0 -554
  186. package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
  187. package/pi-extension/tests/output-router/search.test.js +0 -722
  188. package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
  189. package/router/dist/benchmarks/benchmark-harness.js +0 -92
  190. package/router/dist/benchmarks/benchmarks.d.ts +0 -109
  191. package/router/dist/benchmarks/benchmarks.js +0 -979
  192. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
  193. package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
  194. package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
  195. package/router/dist/benchmarks/command-benchmarks.js +0 -698
  196. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
  197. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
  198. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
  199. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
  200. package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
  201. package/router/dist/benchmarks/context-saving-baseline.js +0 -470
  202. package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
  203. package/router/dist/benchmarks/index-benchmarks.js +0 -862
  204. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
  205. package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
  206. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
  207. package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
  208. package/router/dist/config/config.d.ts +0 -103
  209. package/router/dist/config/config.js +0 -632
  210. package/router/dist/config/router-contract.d.ts +0 -10
  211. package/router/dist/config/router-contract.js +0 -54
  212. package/router/dist/config/schema.d.ts +0 -27
  213. package/router/dist/config/schema.js +0 -648
  214. package/router/dist/config/types.d.ts +0 -573
  215. package/router/dist/config/types.js +0 -41
  216. package/router/dist/evidence/bounded-evidence.d.ts +0 -40
  217. package/router/dist/evidence/bounded-evidence.js +0 -323
  218. package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
  219. package/router/dist/evidence/evidence-range-selector.js +0 -232
  220. package/router/dist/evidence/evidence-search.d.ts +0 -27
  221. package/router/dist/evidence/evidence-search.js +0 -490
  222. package/router/dist/evidence/evidence.d.ts +0 -38
  223. package/router/dist/evidence/evidence.js +0 -200
  224. package/router/dist/evidence/failure-contracts.d.ts +0 -37
  225. package/router/dist/evidence/failure-contracts.js +0 -166
  226. package/router/dist/evidence/line-ranges.d.ts +0 -24
  227. package/router/dist/evidence/line-ranges.js +0 -22
  228. package/router/dist/experiments/local-index.d.ts +0 -64
  229. package/router/dist/experiments/local-index.js +0 -581
  230. package/router/dist/index.d.ts +0 -30
  231. package/router/dist/index.js +0 -32
  232. package/router/dist/local/local-traversal.d.ts +0 -18
  233. package/router/dist/local/local-traversal.js +0 -334
  234. package/router/dist/processing/engine.d.ts +0 -132
  235. package/router/dist/processing/engine.js +0 -533
  236. package/router/dist/processing/reducers.d.ts +0 -280
  237. package/router/dist/processing/reducers.js +0 -1673
  238. package/router/dist/processing/renderers.d.ts +0 -31
  239. package/router/dist/processing/renderers.js +0 -195
  240. package/router/dist/processing/scripts.d.ts +0 -91
  241. package/router/dist/processing/scripts.js +0 -386
  242. package/router/dist/repo/repo-traversal.d.ts +0 -18
  243. package/router/dist/repo/repo-traversal.js +0 -245
  244. package/router/dist/routing/observed-reducers.d.ts +0 -41
  245. package/router/dist/routing/observed-reducers.js +0 -661
  246. package/router/dist/routing/observed-routing.d.ts +0 -26
  247. package/router/dist/routing/observed-routing.js +0 -378
  248. package/router/dist/routing/parsers.d.ts +0 -16
  249. package/router/dist/routing/parsers.js +0 -521
  250. package/router/dist/routing/run-filters.d.ts +0 -60
  251. package/router/dist/routing/run-filters.js +0 -238
  252. package/router/dist/routing/run-reducers.d.ts +0 -49
  253. package/router/dist/routing/run-reducers.js +0 -122
  254. package/router/dist/sandbox/adapter-roots.d.ts +0 -46
  255. package/router/dist/sandbox/adapter-roots.js +0 -66
  256. package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
  257. package/router/dist/sandbox/eryx-python-adapter.js +0 -868
  258. package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
  259. package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
  260. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
  261. package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
  262. package/router/dist/sandbox/script-sandbox.d.ts +0 -134
  263. package/router/dist/sandbox/script-sandbox.js +0 -337
  264. package/router/dist/setup/script-transform-adapters.d.ts +0 -32
  265. package/router/dist/setup/script-transform-adapters.js +0 -278
  266. package/router/dist/tools/batch.d.ts +0 -33
  267. package/router/dist/tools/batch.js +0 -586
  268. package/router/dist/tools/run.d.ts +0 -62
  269. package/router/dist/tools/run.js +0 -1304
  270. package/router/dist/tools/search.d.ts +0 -66
  271. package/router/dist/tools/search.js +0 -1364
  272. package/router/dist/transform/engine.d.ts +0 -168
  273. package/router/dist/transform/engine.js +0 -2072
  274. package/router/dist/vault/vault-index.d.ts +0 -125
  275. package/router/dist/vault/vault-index.js +0 -416
  276. package/router/dist/vault/vault.d.ts +0 -138
  277. package/router/dist/vault/vault.js +0 -630
  278. package/runtime/interaction-contract.md +0 -16
  279. package/skills/discuss/references/checkpoints.md +0 -66
  280. package/skills/execute-work/references/execution-loop.md +0 -77
  281. package/skills/track-work/references/working-record-schema.md +0 -378
  282. package/skills/workflow/references/workflow-loop.md +0 -92
  283. /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
  284. /package/skills/review-artifact/references/{reviewer-prompt.md → independent-artifact-reviewer-contract.md} +0 -0
@@ -2,19 +2,19 @@ import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
 
5
- import { normalizeFreeflowConfig, normalizeLocalFreeflowConfig } from "../../../router/dist/index.js";
5
+ import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
6
+ import { isPiFlowHost } from "./runtime-identity.js";
6
7
 
7
8
  export const VALID_MODES = new Set(["conversation", "workflow", "strict-workflow"]);
8
9
 
9
10
  export const WORKFLOW_COMMANDS = [
10
11
  { command: "discuss", skill: "discuss" },
11
- { command: "discover", skill: "discuss" },
12
+ { command: "action-selection", skill: "action-selection" },
12
13
  { command: "track-work", skill: "track-work" },
13
14
  { command: "write-spec", skill: "write-spec" },
14
15
  { command: "review-artifact", skill: "review-artifact" },
15
16
  { command: "write-plan", skill: "write-plan" },
16
17
  { command: "execute-work", skill: "execute-work" },
17
- { command: "execute-plan", skill: "execute-work" },
18
18
  { command: "simplify-code", skill: "simplify-code" },
19
19
  { command: "migration-work", skill: "migration-work" },
20
20
  { command: "diagnose-failure", skill: "diagnose-failure" },
@@ -31,6 +31,7 @@ export const WORKFLOW_COMMANDS = [
31
31
  export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-skill"];
32
32
 
33
33
  export const FREEFLOW_MODEL_SKILL_NAMES = [
34
+ "action-selection",
34
35
  "bypass",
35
36
  "commit-work",
36
37
  "decision-gate",
@@ -58,63 +59,121 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
58
59
  "write-spec",
59
60
  ];
60
61
 
62
+ export const FREEFLOW_CAPABILITY_SKILL_NAMES = ["cognitive-routing", "context-virtualization", "conversation-history"];
63
+
61
64
  export function freeflowSkillPath(skillName) {
62
65
  return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
63
66
  }
64
67
 
65
- export function freeflowModelSkillPaths() {
66
- return FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
68
+ export function freeflowCapabilitySkillPath(skillName) {
69
+ return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
70
+ }
71
+
72
+ export function freeflowModelSkillPaths(capabilityState = undefined) {
73
+ const paths = FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
74
+ const capabilityStates = {
75
+ "cognitive-routing": capabilityState?.cognitiveRouting,
76
+ "context-virtualization": capabilityState?.contextVirtualization,
77
+ "conversation-history": capabilityState?.conversationHistory,
78
+ };
79
+ for (const skillName of FREEFLOW_CAPABILITY_SKILL_NAMES) {
80
+ if (capabilityStates[skillName]?.effective === true) {
81
+ paths.push(freeflowCapabilitySkillPath(skillName));
82
+ }
83
+ }
84
+ return paths;
67
85
  }
68
86
 
69
- type SessionCoreKey = "enabled" | "interactionContract" | "skillsEnabled";
87
+ type SessionCoreKey =
88
+ "enabled" | "interactionContract" | "skillsEnabled" | "contextVirtualization" | "conversationHistory";
70
89
  type SessionCoreOverrides = Partial<Record<SessionCoreKey, boolean>>;
71
90
 
72
91
  const MODE_STATE_ENTRY = "freeflow-mode";
73
92
  const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
74
- const SESSION_CORE_KEYS = new Set<SessionCoreKey>(["enabled", "interactionContract", "skillsEnabled"]);
93
+ const SESSION_CORE_KEYS = new Set<SessionCoreKey>([
94
+ "enabled",
95
+ "interactionContract",
96
+ "skillsEnabled",
97
+ "contextVirtualization",
98
+ "conversationHistory",
99
+ ]);
75
100
  const RESET_MODE_ARGS = new Set(["reset"]);
76
101
 
77
- export const FREEFLOW_STATUS_TOOL_NAME = "freeflow_status";
78
- export const OUTPUT_ROUTER_TOOL_NAMES = ["freeflow_search", "freeflow_run", "freeflow_batch"];
102
+ export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
103
+ export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
104
+ export const COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-cognitive-routing-runtime-state";
79
105
  export const WORKFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-workflow-bootstrap";
106
+ export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-routing-bootstrap";
107
+ export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
80
108
 
81
109
  let runtimeContextCache = null;
82
110
  let currentModeOverride = null;
83
111
  let currentSessionOverrides: SessionCoreOverrides = {};
84
- let lastRouterConfigWarningKey = null;
112
+
113
+ async function readPromptFile(url: URL): Promise<string | null> {
114
+ try {
115
+ return await readFile(url, "utf8");
116
+ } catch {
117
+ return null;
118
+ }
119
+ }
120
+
85
121
  async function loadRuntimeContext(capabilityState = undefined) {
122
+ const freeflowEnabled = capabilityState?.enabled === true;
86
123
  const interactionContractEnabled = capabilityState?.interactionContract?.effective === true;
87
124
  const skillsEnabled = capabilityState?.skills?.effective === true;
88
- const outputRouterEnabled = capabilityState?.outputRouter?.enabled === true;
89
- const [interactionContract, workflowSkill, outputRouterSkill] = await Promise.all([
125
+ const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
126
+ const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
127
+ const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
128
+ const [
129
+ corePrompt,
130
+ interactionContractPrompt,
131
+ skillsPrompt,
132
+ cognitiveRoutingPrompt,
133
+ contextVirtualizationPrompt,
134
+ conversationHistoryPrompt,
135
+ ] = await Promise.all([
136
+ freeflowEnabled
137
+ ? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
138
+ : Promise.resolve(null),
90
139
  interactionContractEnabled
91
- ? readFile(new URL("../../../runtime/interaction-contract.md", import.meta.url), "utf8")
140
+ ? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
92
141
  : Promise.resolve(null),
93
142
  skillsEnabled
94
- ? readFile(new URL("../../../skills/workflow/SKILL.md", import.meta.url), "utf8")
143
+ ? readPromptFile(new URL("../../../runtime/prompts/skills.md", import.meta.url))
144
+ : Promise.resolve(null),
145
+ cognitiveRoutingEnabled
146
+ ? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
95
147
  : Promise.resolve(null),
96
- outputRouterEnabled
97
- ? readFile(new URL("../../../capabilities/output-router/SKILL.md", import.meta.url), "utf8")
148
+ contextVirtualizationEnabled
149
+ ? readPromptFile(new URL("../../../runtime/prompts/context-virtualization.md", import.meta.url))
150
+ : Promise.resolve(null),
151
+ conversationHistoryEnabled
152
+ ? readPromptFile(new URL("../../../runtime/prompts/conversation-history.md", import.meta.url))
98
153
  : Promise.resolve(null),
99
154
  ]);
100
155
 
101
- return { interactionContract, workflowSkill, outputRouterSkill };
156
+ return {
157
+ corePrompt,
158
+ interactionContractPrompt,
159
+ skillsPrompt,
160
+ cognitiveRoutingPrompt,
161
+ contextVirtualizationPrompt,
162
+ conversationHistoryPrompt,
163
+ };
102
164
  }
103
165
 
104
166
  function runtimeContextCacheSatisfies(capabilityState) {
105
- if (!runtimeContextCache) {
106
- return false;
107
- }
108
- if (capabilityState?.interactionContract?.effective === true && !runtimeContextCache.interactionContract) {
109
- return false;
110
- }
111
- if (capabilityState?.skills?.effective === true && !runtimeContextCache.workflowSkill) {
112
- return false;
113
- }
114
- if (capabilityState?.outputRouter?.enabled === true && !runtimeContextCache.outputRouterSkill) {
115
- return false;
116
- }
117
- return true;
167
+ if (!runtimeContextCache) return false;
168
+ const expected = {
169
+ corePrompt: capabilityState?.enabled === true,
170
+ interactionContractPrompt: capabilityState?.interactionContract?.effective === true,
171
+ skillsPrompt: capabilityState?.skills?.effective === true,
172
+ cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
173
+ contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
174
+ conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
175
+ };
176
+ return Object.entries(expected).every(([key, required]) => !required || Boolean(runtimeContextCache[key]));
118
177
  }
119
178
 
120
179
  export async function refreshRuntimeContext(capabilityState = undefined) {
@@ -129,44 +188,34 @@ export async function getRuntimeContext(capabilityState = undefined) {
129
188
  return refreshRuntimeContext(capabilityState);
130
189
  }
131
190
 
132
- function activeSessionEntries(sessionManager) {
133
- try {
134
- if (typeof sessionManager?.buildContextEntries === "function") {
135
- const entries = sessionManager.buildContextEntries();
136
- if (Array.isArray(entries)) {
137
- return entries;
138
- }
139
- }
140
- if (typeof sessionManager?.getEntries === "function") {
141
- const entries = sessionManager.getEntries();
142
- if (Array.isArray(entries)) {
143
- return entries;
144
- }
145
- }
146
- } catch {
147
- // A missing session snapshot should reload useful context rather than suppress it.
148
- }
149
- return [];
150
- }
191
+ const BOOTSTRAP_COMPONENTS = Object.freeze({
192
+ workflow: "workflow",
193
+ cognitiveRouting: "cognitive-routing",
194
+ });
151
195
 
152
- export function workflowBootstrapMessage(freeflowContext, capabilityState, sessionManager) {
153
- if (capabilityState?.skills?.effective !== true || !freeflowContext?.workflowSkill) {
154
- return undefined;
196
+ function bootstrapEntryComponents(entry) {
197
+ const isCustomMessage = entry?.role === "custom" || entry?.type === "custom_message" || entry?.type === "custom";
198
+ if (!isCustomMessage) return [];
199
+ if (entry.customType === FREEFLOW_BOOTSTRAP_MESSAGE_TYPE) {
200
+ if (Array.isArray(entry.details?.components)) return entry.details.components;
201
+ return [
202
+ ...(entry.content?.includes("<!-- freeflow-bootstrap:workflow -->") ? [BOOTSTRAP_COMPONENTS.workflow] : []),
203
+ ...(entry.content?.includes("<!-- freeflow-bootstrap:cognitive-routing -->")
204
+ ? [BOOTSTRAP_COMPONENTS.cognitiveRouting]
205
+ : []),
206
+ ];
155
207
  }
156
-
157
- const alreadyLoaded = activeSessionEntries(sessionManager).some(
158
- (entry) => entry?.type === "custom_message" && entry?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
159
- );
160
- if (alreadyLoaded) {
161
- return undefined;
208
+ if (entry.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE) {
209
+ return [BOOTSTRAP_COMPONENTS.workflow];
210
+ }
211
+ if (entry.customType === COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE) {
212
+ return [BOOTSTRAP_COMPONENTS.cognitiveRouting];
162
213
  }
214
+ return [];
215
+ }
163
216
 
164
- return {
165
- customType: WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
166
- content: `# Freeflow Workflow Bootstrap\n\n${freeflowContext.workflowSkill.trim()}`,
167
- display: false,
168
- details: { skill: "workflow", source: "first-turn-bootstrap" },
169
- };
217
+ export function filterBootstrapMessage(message) {
218
+ return bootstrapEntryComponents(message).length === 0 ? message : undefined;
170
219
  }
171
220
 
172
221
  function isRecord(value) {
@@ -182,6 +231,14 @@ function validateCoreConfigFields(value) {
182
231
  return "enabled must be a boolean";
183
232
  }
184
233
 
234
+ if (value.contextVirtualization !== undefined && typeof value.contextVirtualization !== "boolean") {
235
+ return "contextVirtualization must be a boolean";
236
+ }
237
+
238
+ if (value.conversationHistory !== undefined && typeof value.conversationHistory !== "boolean") {
239
+ return "conversationHistory must be a boolean";
240
+ }
241
+
185
242
  if (value.interactionContract !== undefined && typeof value.interactionContract !== "boolean") {
186
243
  return "interactionContract must be a boolean";
187
244
  }
@@ -208,6 +265,7 @@ function validateFreeflowConfigShape(value) {
208
265
  return "config must be a JSON object";
209
266
  }
210
267
 
268
+ // Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
211
269
  const allowedKeys = new Set([
212
270
  "enabled",
213
271
  "defaultMode",
@@ -216,6 +274,9 @@ function validateFreeflowConfigShape(value) {
216
274
  "outputRouter",
217
275
  "observedRouting",
218
276
  "scriptTransform",
277
+ "cognitiveRouting",
278
+ "contextVirtualization",
279
+ "conversationHistory",
219
280
  ]);
220
281
  for (const key of Object.keys(value)) {
221
282
  if (!allowedKeys.has(key)) {
@@ -240,7 +301,16 @@ function validateFreeflowLocalConfigShape(value) {
240
301
  return "local config must be a JSON object";
241
302
  }
242
303
 
243
- const allowedKeys = new Set(["enabled", "defaultMode", "interactionContract", "skills", "processing"]);
304
+ const allowedKeys = new Set([
305
+ "enabled",
306
+ "defaultMode",
307
+ "interactionContract",
308
+ "skills",
309
+ "processing",
310
+ "cognitiveRouting",
311
+ "contextVirtualization",
312
+ "conversationHistory",
313
+ ]);
244
314
  for (const key of Object.keys(value)) {
245
315
  if (!allowedKeys.has(key)) {
246
316
  return `unsupported top-level local config key: ${key}`;
@@ -318,6 +388,8 @@ function resolveLayeredValue(repository, local, key, fallback) {
318
388
  function resolveCoreConfig(repository, local) {
319
389
  const enabled = resolveLayeredValue(repository, local, "enabled", true);
320
390
  const interactionContract = resolveLayeredValue(repository, local, "interactionContract", true);
391
+ const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
392
+ const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
321
393
  const defaultMode = resolveLayeredValue(repository, local, "defaultMode", "workflow");
322
394
  const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
323
395
  const localSkills = isRecord(local.skills) ? local.skills : {};
@@ -327,12 +399,16 @@ function resolveCoreConfig(repository, local) {
327
399
  config: {
328
400
  enabled: enabled.value,
329
401
  interactionContract: interactionContract.value,
402
+ contextVirtualization: contextVirtualization.value,
403
+ conversationHistory: conversationHistory.value,
330
404
  skills: { enabled: skillsEnabled.value },
331
405
  defaultMode: defaultMode.value,
332
406
  },
333
407
  sources: {
334
408
  enabled: enabled.source,
335
409
  interactionContract: interactionContract.source,
410
+ contextVirtualization: contextVirtualization.source,
411
+ conversationHistory: conversationHistory.source,
336
412
  skillsEnabled: skillsEnabled.source,
337
413
  defaultMode: defaultMode.source,
338
414
  },
@@ -355,6 +431,8 @@ function resolveSessionCoreConfig(layers) {
355
431
  const sources = layers.sources;
356
432
  const enabled = currentSessionOverrides.enabled;
357
433
  const interactionContract = currentSessionOverrides.interactionContract;
434
+ const contextVirtualization = currentSessionOverrides.contextVirtualization;
435
+ const conversationHistory = currentSessionOverrides.conversationHistory;
358
436
  const skillsEnabled = currentSessionOverrides.skillsEnabled;
359
437
 
360
438
  return {
@@ -362,12 +440,18 @@ function resolveSessionCoreConfig(layers) {
362
440
  enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
363
441
  interactionContract:
364
442
  typeof interactionContract === "boolean" ? interactionContract : configured.interactionContract,
443
+ contextVirtualization:
444
+ typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
445
+ conversationHistory:
446
+ typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
365
447
  skills: { enabled: typeof skillsEnabled === "boolean" ? skillsEnabled : configured.skills.enabled },
366
448
  defaultMode: configured.defaultMode,
367
449
  },
368
450
  sources: {
369
451
  enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
370
452
  interactionContract: typeof interactionContract === "boolean" ? "session" : sources.interactionContract,
453
+ contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
454
+ conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
371
455
  skillsEnabled: typeof skillsEnabled === "boolean" ? "session" : sources.skillsEnabled,
372
456
  defaultMode: sources.defaultMode,
373
457
  },
@@ -400,15 +484,60 @@ export async function readFreeflowConfigLayers(cwd) {
400
484
  };
401
485
  }
402
486
 
403
- export async function readCapabilityState(cwd) {
487
+ export async function readCapabilityState(cwd, host = undefined, extensionHost = undefined) {
404
488
  const layers = await readFreeflowConfigLayers(cwd);
405
- const parsed = layers.repository.valid ? layers.repository.parsed : {};
406
- const normalized = normalizeFreeflowConfig(parsed);
407
489
  const effectiveCore = resolveSessionCoreConfig(layers);
408
490
  const enabled = layers.configured && effectiveCore.config.enabled;
409
491
  const interactionContractConfigEnabled = effectiveCore.config.interactionContract;
410
492
  const skillsConfigEnabled = effectiveCore.config.skills.enabled;
411
- const outputRouterConfigEnabled = normalized.config.outputRouter.enabled;
493
+ const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
494
+ const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
495
+ const skillsEffective = enabled && skillsConfigEnabled;
496
+ const hostSupportsCognitiveRouting = isPiFlowHost(extensionHost);
497
+ const configuredCognitiveRouting = await resolveCognitiveRoutingState(
498
+ layers.repository.parsed,
499
+ layers.local.parsed,
500
+ hostSupportsCognitiveRouting ? host : undefined,
501
+ );
502
+ const disabledReason = enabled
503
+ ? skillsEffective
504
+ ? undefined
505
+ : { code: "disabled" as const, message: "Skills are disabled" }
506
+ : { code: "disabled" as const, message: "Freeflow is disabled" };
507
+ const childCapability = (configuredEnabled) => ({
508
+ enabled: configuredEnabled,
509
+ effective: skillsEffective && configuredEnabled,
510
+ ...(disabledReason ? { blockingReason: disabledReason } : {}),
511
+ });
512
+ const cognitiveRouting = enabled
513
+ ? skillsEffective
514
+ ? !hostSupportsCognitiveRouting && configuredCognitiveRouting.configValid
515
+ ? {
516
+ ...configuredCognitiveRouting,
517
+ effective: false,
518
+ blockingReason: {
519
+ code: "runtime_disabled" as const,
520
+ message: "Cognitive Routing is disabled outside the PiFlow runtime",
521
+ },
522
+ }
523
+ : configuredCognitiveRouting
524
+ : {
525
+ ...configuredCognitiveRouting,
526
+ effective: false,
527
+ blockingReason: {
528
+ code: "disabled" as const,
529
+ message: "Skills are disabled",
530
+ },
531
+ }
532
+ : {
533
+ ...configuredCognitiveRouting,
534
+ enabled: false,
535
+ effective: false,
536
+ blockingReason: {
537
+ code: "disabled" as const,
538
+ message: "Freeflow is disabled",
539
+ },
540
+ };
412
541
  return {
413
542
  configured: layers.configured,
414
543
  repositoryConfigured: layers.repositoryConfigured,
@@ -434,69 +563,15 @@ export async function readCapabilityState(cwd) {
434
563
  enabled: skillsConfigEnabled,
435
564
  effective: enabled && skillsConfigEnabled,
436
565
  },
437
- outputRouter: {
438
- enabled: enabled && outputRouterConfigEnabled,
439
- configEnabled: outputRouterConfigEnabled,
440
- },
566
+ contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
567
+ conversationHistory: childCapability(conversationHistoryConfigEnabled),
568
+ hostSupportsCognitiveRouting,
569
+ cognitiveRouting,
441
570
  };
442
571
  }
443
572
 
444
573
  export const readRuntimeState = readCapabilityState;
445
574
 
446
- export async function readOutputRouterConfig(cwd) {
447
- const layers = await readFreeflowConfigLayers(cwd);
448
- const parsed = layers.repository.valid ? layers.repository.parsed : {};
449
- const localParsed = layers.local.valid ? layers.local.parsed : {};
450
- const normalized = normalizeFreeflowConfig(parsed);
451
- const local = normalizeLocalFreeflowConfig(localParsed);
452
- const freeflowEnabled = layers.configured && layers.coreConfig.enabled;
453
- const effectiveConfig = freeflowEnabled
454
- ? normalized.config
455
- : {
456
- ...normalized.config,
457
- outputRouter: { ...normalized.config.outputRouter, enabled: false },
458
- observedRouting: {
459
- ...normalized.config.observedRouting,
460
- enabled: false,
461
- },
462
- scriptTransform: {
463
- ...normalized.config.scriptTransform,
464
- enabled: false,
465
- },
466
- };
467
- const configWarnings = [...normalized.warnings];
468
- if (layers.repository.exists && !layers.repository.valid) {
469
- configWarnings.unshift(
470
- `.freeflow/config.json could not be parsed; Freeflow runtime is inactive. ${layers.repository.parseError ?? ""}`.trim(),
471
- );
472
- }
473
- if (layers.local.exists && !layers.local.valid) {
474
- configWarnings.unshift(
475
- `.freeflow/local.json could not be parsed; Freeflow runtime is inactive. ${layers.local.parseError ?? ""}`.trim(),
476
- );
477
- }
478
- return {
479
- config: effectiveConfig.outputRouter,
480
- freeflowConfig: effectiveConfig,
481
- localConfig: local.config,
482
- warnings: [...configWarnings, ...local.warnings],
483
- };
484
- }
485
-
486
- export function notifyRouterConfigWarnings(ctx, routerConfigResult) {
487
- if (!routerConfigResult.warnings.length) {
488
- return;
489
- }
490
-
491
- const key = routerConfigResult.warnings.join("\n");
492
- if (key === lastRouterConfigWarningKey) {
493
- return;
494
- }
495
-
496
- lastRouterConfigWarningKey = key;
497
- ctx.ui.notify(`Freeflow config warning: ${routerConfigResult.warnings.join(" ")}`, "warning");
498
- }
499
-
500
575
  export function restoreModeOverride(ctx) {
501
576
  currentModeOverride = null;
502
577
  currentSessionOverrides = {};
@@ -538,7 +613,13 @@ export async function readModeState(cwd) {
538
613
  };
539
614
  }
540
615
 
541
- export function setModeStatus(ctx, modeState, capabilityState = undefined) {
616
+ export function setModeStatus(
617
+ ctx,
618
+ modeState,
619
+ capabilityState = undefined,
620
+ cognitiveRoutingRuntime = undefined,
621
+ options: { cognitiveRoutingStartupPending?: boolean } = {},
622
+ ) {
542
623
  if (capabilityState && !capabilityState.configured) {
543
624
  ctx.ui.setStatus("freeflow", capabilityState.configExists ? "freeflow: config error" : "freeflow: setup needed");
544
625
  return;
@@ -560,8 +641,39 @@ export function setModeStatus(ctx, modeState, capabilityState = undefined) {
560
641
  } else if (capabilityState?.configSources?.skillsEnabled === "session") {
561
642
  active.push("skills off (session)");
562
643
  }
563
- if (capabilityState?.outputRouter.enabled) {
564
- active.push("router");
644
+ const cognitiveRouting = capabilityState?.cognitiveRouting;
645
+ const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
646
+ const startupSelectionSuppressesCognitiveRouting =
647
+ ctx?.modelStateProvenance?.explicitModel === true || ctx?.modelStateProvenance?.explicitThinking === true;
648
+ if (cognitiveRoutingActive) {
649
+ const profile = cognitiveRoutingRuntime.activeProfile;
650
+ const control =
651
+ cognitiveRoutingRuntime.controlMode === "manual-standard" ||
652
+ cognitiveRoutingRuntime.controlMode === "manual-reasoning"
653
+ ? "manual hold"
654
+ : "automatic";
655
+ active.push(`${profile} · ${control}`);
656
+ } else if (cognitiveRouting?.enabled === true) {
657
+ if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
658
+ active.push("cognitive disabled · PiFlow only");
659
+ } else if (
660
+ cognitiveRouting.effective === true &&
661
+ cognitiveRoutingRuntime === undefined &&
662
+ options.cognitiveRoutingStartupPending === true &&
663
+ !startupSelectionSuppressesCognitiveRouting
664
+ ) {
665
+ const startupProfile = cognitiveRouting.sessionStart?.profile ?? "standard";
666
+ active.push(`${startupProfile} · pending`);
667
+ } else {
668
+ const reason =
669
+ cognitiveRouting?.effective === true
670
+ ? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
671
+ : (cognitiveRouting.blockingReason?.code ?? "unavailable");
672
+ active.push(`cognitive blocked · ${reason}`);
673
+ }
674
+ }
675
+ if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
676
+ active.push("context");
565
677
  }
566
678
  ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "idle"}`);
567
679
  }
@@ -585,175 +697,121 @@ export function skillPrompt(skill, args) {
585
697
  return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
586
698
  }
587
699
 
588
- function outputRouterModeGuidance(mode, skillsEnabled = true) {
589
- if (!skillsEnabled) {
590
- return "Freeflow Skills are disabled: no Freeflow workflow mode is active; apply only output-router evidence guidance.";
591
- }
592
- if (mode === "conversation") {
593
- return "conversation mode: keep routed-tool guidance soft; answer questions directly.";
594
- }
595
- if (mode === "strict-workflow") {
596
- return "strict-workflow mode: strongest guidance; prefer exact, recoverable routed evidence for risky work.";
597
- }
598
- return "workflow mode: prefer routed tools for exploration and likely-large command output.";
599
- }
600
-
601
- function outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
602
- const safetyNetText =
603
- routerConfigResult.config.postToolRouting === "off"
604
- ? ""
605
- : "\n\nOutput-router config note: large native read/bash outputs may be vaulted and replaced with labeled routed output. Use freeflow_search with the output id to recover exact content.";
606
-
607
- return `## Loaded Output Router Skill
608
-
609
- Mode guidance: ${outputRouterModeGuidance(modeState.effectiveMode, capabilityState.skills.effective)}${safetyNetText}
610
-
611
- \`\`\`md
612
- ${freeflowContext.outputRouterSkill.trim()}
613
- \`\`\``;
614
- }
615
-
616
- function capabilityContext(capabilityState) {
617
- const sessionSuffix = (source) => (source === "session" ? " (session override)" : "");
618
- const interactionContract = `${capabilityState.interactionContract.effective ? "enabled" : "disabled"}${sessionSuffix(
619
- capabilityState.configSources.interactionContract,
620
- )}`;
621
- const skills = `${capabilityState.skills.effective ? "enabled" : "disabled"}${sessionSuffix(
622
- capabilityState.configSources.skillsEnabled,
623
- )}`;
624
- const outputRouter = capabilityState.outputRouter.enabled ? "enabled" : "disabled";
625
- return `## Freeflow Capabilities
700
+ type CognitiveRoutingRuntimeSnapshot = {
701
+ effective?: boolean;
702
+ activeProfile?: unknown;
703
+ controlMode?: unknown;
704
+ };
626
705
 
627
- - Interaction contract: ${interactionContract}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
628
- - Skills: ${skills}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
629
- - Output router: ${outputRouter}. Configure with \`/freeflow settings\` or \`/output-router\`; inspect with \`/output-router status\`.
706
+ type FreeflowContextMessage = {
707
+ customType?: unknown;
708
+ [key: string]: unknown;
709
+ };
630
710
 
631
- Disabled capabilities are named only for status/config awareness. Capability-specific instructions and tools are active only while that capability is enabled.`;
711
+ function publicCognitiveRoutingControl(controlMode) {
712
+ if (controlMode === "automatic") return "automatic";
713
+ if (controlMode === "manual-standard" || controlMode === "manual-reasoning") return "manual";
714
+ return "unavailable";
632
715
  }
633
716
 
634
- function hasModelFacingCapability(capabilityState) {
635
- return (
636
- capabilityState.interactionContract.effective ||
637
- capabilityState.skills.effective ||
638
- capabilityState.outputRouter.enabled
639
- );
717
+ function publicCognitiveRoutingProfile(activeProfile, effective) {
718
+ if (effective !== true) return "unavailable";
719
+ return activeProfile === "standard" || activeProfile === "reasoning" ? activeProfile : "unavailable";
640
720
  }
641
721
 
642
- function modeOverlayContext(mode) {
643
- if (mode === "conversation") {
644
- return `
645
-
646
- ## Conversation Mode Boundary
647
-
648
- Conversation mode is active and read-only.
649
-
650
- Do not call write, edit, or mutating tools. Do not create, delete, commit, push, or change repository, system, external, or durable state.
651
-
652
- A mutation request does not switch mode, and an execution skill does not override this boundary. Explain that conversation mode is read-only and ask the user to switch to workflow or strict-workflow.`;
653
- }
654
-
655
- if (mode === "strict-workflow") {
656
- return `
657
-
658
- ## Strict Workflow Overlay
659
-
660
- Strict Workflow is active. Use the adaptive Workflow, but increase decision, evidence, verification, and checkpoint pressure at high-risk or hard-to-reverse boundaries.
661
-
662
- For work affecting security, privacy, billing, data loss, migrations, public interfaces, compatibility, deployment, or architecture:
663
-
664
- - stop for any user-owned choice or source conflict;
665
- - inspect the relevant risk surface before crossing the boundary;
666
- - select only artifacts, checkpoints, and independent review that materially reduce risk;
667
- - verify at the affected boundary before claiming success.
668
-
669
- Do not manufacture ceremony for low-risk, reversible work. Strict Workflow does not authorize mutation, bypass safety, or make every implementation detail a user decision.`;
670
- }
671
-
672
- return "";
722
+ function publicCapabilityStatus(capability) {
723
+ if (capability?.effective === true) return "active";
724
+ if (!capability) return "unavailable";
725
+ const blockingCode = capability.blockingReason?.code;
726
+ if (blockingCode && blockingCode !== "disabled") return "unavailable";
727
+ return "inactive";
673
728
  }
674
729
 
675
- function activeModeContext(modeState) {
676
- return `## Freeflow Mode State
677
-
678
- Repository default mode: \`${modeState.repositoryDefaultMode}\` (${modeState.repositoryDefaultModeSource}).
679
- Personal default override: \`${modeState.personalDefaultMode ?? "none"}\`.
680
- Configured default mode: \`${modeState.defaultMode}\` (${modeSourceLabel(modeState.defaultModeSource)}).
681
- Session mode override: \`${modeState.sessionMode ?? "none"}\`.
682
- Resolved mode: \`${modeState.resolvedMode}\`.
683
- Effective Freeflow mode: \`${modeState.effectiveMode}\`.
684
-
685
- Mode behavior:
686
- - \`conversation\`: answer, discuss, critique, and inspect read-only; require a mode change before mutating state.
687
- - \`workflow\`: use the adaptive workflow for consequential or mutating work.
688
- - \`strict-workflow\`: use the same workflow with stronger decision, evidence, and checkpoint pressure at high-risk or hard-to-reverse boundaries.
730
+ export function freeflowRuntimeStateMessage(
731
+ modeState,
732
+ capabilityState,
733
+ cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
734
+ ) {
735
+ const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
736
+ const profile = publicCognitiveRoutingProfile(
737
+ cognitiveRoutingRuntime?.activeProfile,
738
+ cognitiveRoutingEffective && cognitiveRoutingRuntime?.effective === true,
739
+ );
740
+ const control =
741
+ profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
742
+ const defaultMode = modeState?.defaultMode ?? "workflow";
743
+ const activeMode = modeState?.effectiveMode ?? "inactive";
689
744
 
690
- Task type, risk classification, and direct skill calls do not change mode. Recommend another mode when useful; the user decides.
691
- Do not announce mode on every reply. Mention it when the user asks, configuration is discussed, or it changes the next action.${modeOverlayContext(modeState.effectiveMode)}`;
745
+ return {
746
+ role: "custom",
747
+ customType: FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE,
748
+ content: [
749
+ "# Freeflow Runtime State",
750
+ "",
751
+ "This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
752
+ "",
753
+ `Default mode: \`${defaultMode}\``,
754
+ `Active mode: \`${activeMode}\``,
755
+ "",
756
+ "Capabilities:",
757
+ `- Interaction Contract: ${publicCapabilityStatus(capabilityState?.interactionContract)}`,
758
+ `- Skills: ${publicCapabilityStatus(capabilityState?.skills)}`,
759
+ `- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
760
+ `- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
761
+ `- Cognitive Routing: ${publicCapabilityStatus(capabilityState?.cognitiveRouting)}`,
762
+ "",
763
+ "Cognitive Routing:",
764
+ `- Control: \`${control}\``,
765
+ `- Profile: \`${profile}\``,
766
+ ].join("\n"),
767
+ display: false,
768
+ details: { source: "provider-request-runtime-state" },
769
+ };
692
770
  }
693
771
 
694
- function inactiveModeContext(modeState) {
695
- return `## Freeflow Mode State
696
-
697
- Repository default mode: \`${modeState.repositoryDefaultMode}\` (${modeState.repositoryDefaultModeSource}).
698
- Personal default override: \`${modeState.personalDefaultMode ?? "none"}\`.
699
- Configured default mode: \`${modeState.defaultMode}\` (${modeSourceLabel(modeState.defaultModeSource)}).
700
- Session mode override: \`${modeState.sessionMode ?? "none"}\`.
701
- Resolved mode: \`${modeState.resolvedMode}\` (inactive because Skills are disabled).
702
- Effective Freeflow mode: \`none\`.
703
-
704
- Freeflow workflow modes are dormant until Skills are enabled with \`/freeflow settings\`.`;
772
+ export function withoutFreeflowRuntimeState(messages: readonly FreeflowContextMessage[] | undefined) {
773
+ return (Array.isArray(messages) ? messages : []).filter(
774
+ (message) =>
775
+ message?.customType !== FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
776
+ message?.customType !== COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
777
+ );
705
778
  }
706
779
 
707
- function controlPlaneContext(modeState, capabilityState) {
708
- return `# Freeflow Control Plane
709
-
710
- Freeflow is enabled for this repo, but no model-facing capabilities are enabled.
711
- These lines are status/config awareness only; do not apply Freeflow workflow or output-router behavior.
712
-
713
- ${inactiveModeContext(modeState)}
714
-
715
- ${capabilityContext(capabilityState)}
716
-
717
- Use \`/freeflow settings\` to enable the Interaction Contract, Skills, or Output Router. The read-only \`freeflow_status\` diagnostic may be available so the model can answer setup/status questions.`;
780
+ export function withFreeflowRuntimeState(
781
+ messages: readonly FreeflowContextMessage[] | undefined,
782
+ modeState,
783
+ capabilityState,
784
+ cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
785
+ ) {
786
+ return [
787
+ ...withoutFreeflowRuntimeState(messages),
788
+ freeflowRuntimeStateMessage(modeState, capabilityState, cognitiveRoutingRuntime),
789
+ ];
718
790
  }
719
791
 
720
- export function runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
721
- if (!capabilityState.configured) {
792
+ export function runtimeContext(freeflowContext, capabilityState) {
793
+ if (capabilityState?.configured !== true || capabilityState?.enabled !== true || !freeflowContext?.corePrompt) {
722
794
  return "";
723
795
  }
724
796
 
725
- if (!capabilityState.enabled) {
726
- return `# Freeflow Disabled
727
-
728
- Freeflow is disabled by \`.freeflow/config.json\` for this repo. Do not apply the Freeflow Interaction Contract, workflow, or output-router behavior unless the user re-enables Freeflow with \`/freeflow enable\` or \`/freeflow settings\`.
729
-
730
- These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.`;
797
+ const blocks = [];
798
+ if (freeflowContext?.corePrompt) blocks.push(freeflowContext.corePrompt.trim());
799
+ if (capabilityState.interactionContract?.effective === true && freeflowContext?.interactionContractPrompt) {
800
+ blocks.push(freeflowContext.interactionContractPrompt.trim());
731
801
  }
732
-
733
- if (!hasModelFacingCapability(capabilityState)) {
734
- return controlPlaneContext(modeState, capabilityState);
802
+ if (capabilityState.skills?.effective === true && freeflowContext?.skillsPrompt) {
803
+ blocks.push(freeflowContext.skillsPrompt.trim());
735
804
  }
736
-
737
- const modeText = capabilityState.skills.effective ? activeModeContext(modeState) : inactiveModeContext(modeState);
738
- const interactionContractText = capabilityState.interactionContract.effective
739
- ? `\n\n${freeflowContext.interactionContract.trim()}`
740
- : "";
741
- const routerText =
742
- capabilityState.outputRouter.enabled && routerConfigResult.config.enabled
743
- ? `\n\n${outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState)}`
744
- : "";
745
-
746
- return `# Freeflow Runtime Context
747
-
748
- Freeflow Pi extension loaded this before the agent turn.
749
- Runtime delivery: confirmed for this Pi \`before_agent_start\` invocation.
750
- These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.
751
-
752
- ${modeText}
753
-
754
- ${capabilityContext(capabilityState)}${interactionContractText}${routerText}
755
-
756
- This Pi extension loads enabled runtime context before every agent turn and routes commands only; it does not enforce policy, block tools, grant permissions, or create repo-local hooks.`;
805
+ if (capabilityState.cognitiveRouting?.effective === true && freeflowContext?.cognitiveRoutingPrompt) {
806
+ blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
807
+ }
808
+ if (capabilityState.contextVirtualization?.effective === true && freeflowContext?.contextVirtualizationPrompt) {
809
+ blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
810
+ }
811
+ if (capabilityState.conversationHistory?.effective === true && freeflowContext?.conversationHistoryPrompt) {
812
+ blocks.push(freeflowContext.conversationHistoryPrompt.trim());
813
+ }
814
+ return blocks.filter(Boolean).join("\n\n");
757
815
  }
758
816
 
759
817
  export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean | null, ctx, pi) {
@@ -781,7 +839,7 @@ export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean
781
839
  changed: true,
782
840
  reloadRequired: key === "enabled" || key === "skillsEnabled",
783
841
  sessionOverrides: { ...currentSessionOverrides },
784
- capabilityState: await readCapabilityState(ctx.cwd),
842
+ capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
785
843
  };
786
844
  }
787
845
 
@@ -819,7 +877,7 @@ export async function setSessionMode(mode, ctx, pi) {
819
877
 
820
878
  export async function handleModeCommand(args, ctx, pi) {
821
879
  const arg = args?.trim();
822
- const capabilityState = await readCapabilityState(ctx.cwd);
880
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
823
881
  const inactiveModeState = await readModeState(ctx.cwd);
824
882
 
825
883
  if (!capabilityState.configured) {