@hassangameryt/freeflow 0.4.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 (285) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/.codex-plugin/plugin.json +2 -1
  4. package/README.md +150 -155
  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 +17 -13
  9. package/hooks/freeflow-runtime-context.mjs +393 -159
  10. package/hooks/hooks.json +26 -1
  11. package/hooks/tests/check-runtime-context-hook.sh +223 -54
  12. package/package.json +25 -16
  13. package/pi-extension/dist/cognitive-routing/commands.js +96 -0
  14. package/pi-extension/dist/cognitive-routing/config.js +236 -0
  15. package/pi-extension/dist/cognitive-routing/controller.js +862 -0
  16. package/pi-extension/dist/cognitive-routing/history.js +439 -0
  17. package/pi-extension/dist/cognitive-routing/host.js +126 -0
  18. package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
  19. package/pi-extension/dist/cognitive-routing/tool.js +211 -0
  20. package/pi-extension/dist/cognitive-routing/types.js +6 -0
  21. package/pi-extension/dist/context-virtualization/commands.js +89 -0
  22. package/pi-extension/dist/context-virtualization/projector.js +42 -0
  23. package/pi-extension/dist/context-virtualization/runtime.js +356 -0
  24. package/pi-extension/dist/context-virtualization/state.js +57 -0
  25. package/pi-extension/dist/context-virtualization/types.js +10 -0
  26. package/pi-extension/dist/conversation-history/passages.js +66 -0
  27. package/pi-extension/dist/conversation-history/ranking.js +105 -0
  28. package/pi-extension/dist/conversation-history/runtime.js +226 -0
  29. package/pi-extension/dist/conversation-history/search.js +56 -0
  30. package/pi-extension/dist/conversation-history/types.js +1 -0
  31. package/pi-extension/dist/freeflow-context/resolver.js +120 -0
  32. package/pi-extension/dist/freeflow-context/runtime.js +80 -0
  33. package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
  34. package/pi-extension/dist/freeflow-context/tool.js +308 -0
  35. package/pi-extension/dist/freeflow-context/types.js +12 -0
  36. package/pi-extension/dist/freeflow-context/visibility.js +28 -0
  37. package/pi-extension/dist/index.js +516 -98
  38. package/pi-extension/dist/runtime/runtime-context.js +318 -271
  39. package/pi-extension/dist/runtime/runtime-identity.js +5 -0
  40. package/pi-extension/dist/settings/settings-tui.js +78 -0
  41. package/pi-extension/dist/settings/settings-ui.js +593 -563
  42. package/pi-extension/dist/ui/text-component.js +57 -0
  43. package/pi-extension/src/cognitive-routing/commands.ts +119 -0
  44. package/pi-extension/src/cognitive-routing/config.ts +307 -0
  45. package/pi-extension/src/cognitive-routing/controller.ts +1118 -0
  46. package/pi-extension/src/cognitive-routing/history.ts +638 -0
  47. package/pi-extension/src/cognitive-routing/host.ts +172 -0
  48. package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
  49. package/pi-extension/src/cognitive-routing/tool.ts +272 -0
  50. package/pi-extension/src/cognitive-routing/types.ts +89 -0
  51. package/pi-extension/src/context-virtualization/commands.ts +111 -0
  52. package/pi-extension/src/context-virtualization/projector.ts +62 -0
  53. package/pi-extension/src/context-virtualization/runtime.ts +406 -0
  54. package/pi-extension/src/context-virtualization/state.ts +79 -0
  55. package/pi-extension/src/context-virtualization/types.ts +92 -0
  56. package/pi-extension/src/conversation-history/passages.ts +81 -0
  57. package/pi-extension/src/conversation-history/ranking.ts +155 -0
  58. package/pi-extension/src/conversation-history/runtime.ts +250 -0
  59. package/pi-extension/src/conversation-history/search.ts +79 -0
  60. package/pi-extension/src/conversation-history/types.ts +31 -0
  61. package/pi-extension/src/freeflow-context/resolver.ts +139 -0
  62. package/pi-extension/src/freeflow-context/runtime.ts +100 -0
  63. package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
  64. package/pi-extension/src/freeflow-context/tool.ts +360 -0
  65. package/pi-extension/src/freeflow-context/types.ts +70 -0
  66. package/pi-extension/src/freeflow-context/visibility.ts +53 -0
  67. package/pi-extension/src/index.ts +553 -101
  68. package/pi-extension/src/runtime/runtime-context.ts +339 -281
  69. package/pi-extension/src/runtime/runtime-identity.ts +8 -0
  70. package/pi-extension/src/settings/settings-tui.ts +93 -0
  71. package/pi-extension/src/settings/settings-ui.ts +700 -613
  72. package/pi-extension/src/ui/text-component.ts +66 -0
  73. package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
  74. package/pi-extension/tests/cognitive-routing/controller.test.js +1099 -0
  75. package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1071 -0
  76. package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
  77. package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
  78. package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
  79. package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +236 -0
  80. package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
  81. package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
  82. package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
  83. package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
  84. package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
  85. package/pi-extension/tests/conversation-history/search.test.js +97 -0
  86. package/pi-extension/tests/integration/pi-extension.test.js +928 -2047
  87. package/pi-extension/tests/integration/prompt-architecture.test.js +305 -0
  88. package/runtime/prompts/cognitive-routing.md +9 -0
  89. package/runtime/prompts/context-virtualization.md +3 -0
  90. package/runtime/prompts/conversation-history.md +3 -0
  91. package/runtime/prompts/core.md +13 -0
  92. package/runtime/prompts/interaction-contract.md +7 -0
  93. package/runtime/prompts/skills.md +65 -0
  94. package/skills/action-selection/SKILL.md +91 -0
  95. package/skills/bypass/SKILL.md +3 -2
  96. package/skills/commit-work/SKILL.md +1 -1
  97. package/skills/commit-work/references/staging-decisions.md +1 -1
  98. package/skills/decision-gate/SKILL.md +1 -1
  99. package/skills/design-for-depth/SKILL.md +14 -33
  100. package/skills/design-for-depth/references/design-pressure-signals.md +1 -1
  101. package/skills/design-for-depth/references/interface-design-loop.md +1 -1
  102. package/skills/design-for-depth/references/software-design-philosophy.md +1 -1
  103. package/skills/diagnose-failure/SKILL.md +20 -14
  104. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +1 -3
  105. package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +1 -1
  106. package/skills/discuss/SKILL.md +34 -22
  107. package/skills/discuss/references/discussion-continuity.md +71 -0
  108. package/skills/evaluate-skill/SKILL.md +5 -5
  109. package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +42 -2
  110. package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
  111. package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
  112. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
  113. package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
  114. package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
  115. package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
  116. package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
  117. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
  118. package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
  119. package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
  120. package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
  121. package/skills/execute-work/SKILL.md +18 -15
  122. package/skills/execute-work/references/code-practices.md +1 -1
  123. package/skills/execute-work/references/execute-work-edges.md +42 -0
  124. package/skills/finish-branch/SKILL.md +2 -2
  125. package/skills/finish-branch/references/integration-options.md +1 -1
  126. package/skills/handoff/SKILL.md +3 -3
  127. package/skills/launch-work/SKILL.md +1 -1
  128. package/skills/launch-work/references/launch-readiness.md +2 -2
  129. package/skills/migration-work/SKILL.md +2 -2
  130. package/skills/migration-work/references/migration-lifecycle.md +1 -1
  131. package/skills/mode-contract/SKILL.md +32 -10
  132. package/skills/release-work/SKILL.md +1 -1
  133. package/skills/release-work/references/release-evidence.md +1 -1
  134. package/skills/review-artifact/SKILL.md +28 -26
  135. package/skills/review-work/SKILL.md +28 -26
  136. package/skills/review-work/references/{reviewer-prompt.md → independent-work-reviewer-contract.md} +1 -1
  137. package/skills/review-work/references/security-risk-lens.md +1 -1
  138. package/skills/setup-freeflow/SKILL.md +6 -10
  139. package/skills/setup-freeflow/references/activation-contract.md +5 -10
  140. package/skills/setup-freeflow/references/host-setup.md +3 -7
  141. package/skills/simplify-code/SKILL.md +1 -1
  142. package/skills/simplify-code/references/simplification-patterns.md +1 -1
  143. package/skills/tdd/SKILL.md +18 -38
  144. package/skills/tdd/references/test-design.md +2 -2
  145. package/skills/track-work/SKILL.md +362 -58
  146. package/skills/track-work/scripts/lib/codec.mjs +570 -0
  147. package/skills/track-work/scripts/lib/commands.mjs +568 -0
  148. package/skills/track-work/scripts/lib/contract.mjs +303 -0
  149. package/skills/track-work/scripts/lib/model.mjs +506 -0
  150. package/skills/track-work/scripts/lib/operations.mjs +965 -0
  151. package/skills/track-work/scripts/lib/record-store.mjs +264 -0
  152. package/skills/track-work/scripts/lib/result.mjs +37 -0
  153. package/skills/track-work/scripts/lib/rewrites.mjs +740 -0
  154. package/skills/track-work/scripts/lib/schema.mjs +277 -0
  155. package/skills/track-work/scripts/lib/source-inventory.mjs +162 -0
  156. package/skills/track-work/scripts/lib/views.mjs +443 -0
  157. package/skills/track-work/scripts/lib/workspace.mjs +134 -0
  158. package/skills/track-work/scripts/working-record.mjs +122 -0
  159. package/skills/verify-work/SKILL.md +14 -2
  160. package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
  161. package/skills/verify-work/references/integration-evidence.md +1 -1
  162. package/skills/verify-work/references/performance-evidence.md +1 -1
  163. package/skills/workflow/SKILL.md +105 -53
  164. package/skills/workflow/references/domain-skill-composition.md +22 -42
  165. package/skills/write-plan/SKILL.md +1 -1
  166. package/skills/write-skill/SKILL.md +3 -2
  167. package/skills/write-skill/references/progressive-disclosure.md +17 -3
  168. package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
  169. package/pi-extension/dist/output-router/native-safety-net.js +0 -216
  170. package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
  171. package/pi-extension/dist/output-router/renderers.js +0 -1023
  172. package/pi-extension/dist/output-router/router-tools.js +0 -554
  173. package/pi-extension/dist/output-router/schemas.js +0 -383
  174. package/pi-extension/dist/output-router/status.js +0 -744
  175. package/pi-extension/dist/output-router/utils.js +0 -502
  176. package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
  177. package/pi-extension/src/output-router/native-safety-net.ts +0 -248
  178. package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
  179. package/pi-extension/src/output-router/renderers.ts +0 -1108
  180. package/pi-extension/src/output-router/router-tools.ts +0 -579
  181. package/pi-extension/src/output-router/schemas.ts +0 -387
  182. package/pi-extension/src/output-router/status.ts +0 -791
  183. package/pi-extension/src/output-router/utils.ts +0 -554
  184. package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
  185. package/pi-extension/tests/output-router/search.test.js +0 -722
  186. package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
  187. package/router/dist/benchmarks/benchmark-harness.js +0 -92
  188. package/router/dist/benchmarks/benchmarks.d.ts +0 -109
  189. package/router/dist/benchmarks/benchmarks.js +0 -979
  190. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
  191. package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
  192. package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
  193. package/router/dist/benchmarks/command-benchmarks.js +0 -698
  194. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
  195. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
  196. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
  197. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
  198. package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
  199. package/router/dist/benchmarks/context-saving-baseline.js +0 -470
  200. package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
  201. package/router/dist/benchmarks/index-benchmarks.js +0 -862
  202. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
  203. package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
  204. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
  205. package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
  206. package/router/dist/config/config.d.ts +0 -103
  207. package/router/dist/config/config.js +0 -632
  208. package/router/dist/config/router-contract.d.ts +0 -10
  209. package/router/dist/config/router-contract.js +0 -54
  210. package/router/dist/config/schema.d.ts +0 -27
  211. package/router/dist/config/schema.js +0 -648
  212. package/router/dist/config/types.d.ts +0 -573
  213. package/router/dist/config/types.js +0 -41
  214. package/router/dist/evidence/bounded-evidence.d.ts +0 -40
  215. package/router/dist/evidence/bounded-evidence.js +0 -323
  216. package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
  217. package/router/dist/evidence/evidence-range-selector.js +0 -232
  218. package/router/dist/evidence/evidence-search.d.ts +0 -27
  219. package/router/dist/evidence/evidence-search.js +0 -490
  220. package/router/dist/evidence/evidence.d.ts +0 -38
  221. package/router/dist/evidence/evidence.js +0 -200
  222. package/router/dist/evidence/failure-contracts.d.ts +0 -37
  223. package/router/dist/evidence/failure-contracts.js +0 -166
  224. package/router/dist/evidence/line-ranges.d.ts +0 -24
  225. package/router/dist/evidence/line-ranges.js +0 -22
  226. package/router/dist/experiments/local-index.d.ts +0 -64
  227. package/router/dist/experiments/local-index.js +0 -581
  228. package/router/dist/index.d.ts +0 -30
  229. package/router/dist/index.js +0 -32
  230. package/router/dist/local/local-traversal.d.ts +0 -18
  231. package/router/dist/local/local-traversal.js +0 -334
  232. package/router/dist/processing/engine.d.ts +0 -132
  233. package/router/dist/processing/engine.js +0 -533
  234. package/router/dist/processing/reducers.d.ts +0 -280
  235. package/router/dist/processing/reducers.js +0 -1673
  236. package/router/dist/processing/renderers.d.ts +0 -31
  237. package/router/dist/processing/renderers.js +0 -195
  238. package/router/dist/processing/scripts.d.ts +0 -91
  239. package/router/dist/processing/scripts.js +0 -386
  240. package/router/dist/repo/repo-traversal.d.ts +0 -18
  241. package/router/dist/repo/repo-traversal.js +0 -245
  242. package/router/dist/routing/observed-reducers.d.ts +0 -41
  243. package/router/dist/routing/observed-reducers.js +0 -661
  244. package/router/dist/routing/observed-routing.d.ts +0 -26
  245. package/router/dist/routing/observed-routing.js +0 -378
  246. package/router/dist/routing/parsers.d.ts +0 -16
  247. package/router/dist/routing/parsers.js +0 -521
  248. package/router/dist/routing/run-filters.d.ts +0 -60
  249. package/router/dist/routing/run-filters.js +0 -238
  250. package/router/dist/routing/run-reducers.d.ts +0 -49
  251. package/router/dist/routing/run-reducers.js +0 -122
  252. package/router/dist/sandbox/adapter-roots.d.ts +0 -46
  253. package/router/dist/sandbox/adapter-roots.js +0 -66
  254. package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
  255. package/router/dist/sandbox/eryx-python-adapter.js +0 -868
  256. package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
  257. package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
  258. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
  259. package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
  260. package/router/dist/sandbox/script-sandbox.d.ts +0 -134
  261. package/router/dist/sandbox/script-sandbox.js +0 -337
  262. package/router/dist/setup/script-transform-adapters.d.ts +0 -32
  263. package/router/dist/setup/script-transform-adapters.js +0 -278
  264. package/router/dist/tools/batch.d.ts +0 -33
  265. package/router/dist/tools/batch.js +0 -586
  266. package/router/dist/tools/run.d.ts +0 -62
  267. package/router/dist/tools/run.js +0 -1304
  268. package/router/dist/tools/search.d.ts +0 -66
  269. package/router/dist/tools/search.js +0 -1364
  270. package/router/dist/transform/engine.d.ts +0 -168
  271. package/router/dist/transform/engine.js +0 -2072
  272. package/router/dist/vault/vault-index.d.ts +0 -125
  273. package/router/dist/vault/vault-index.js +0 -416
  274. package/router/dist/vault/vault.d.ts +0 -138
  275. package/router/dist/vault/vault.js +0 -630
  276. package/runtime/interaction-contract.md +0 -16
  277. package/skills/discuss/references/checkpoints.md +0 -66
  278. package/skills/execute-work/references/execution-loop.md +0 -77
  279. package/skills/output-router/SKILL.md +0 -206
  280. package/skills/output-router/references/safety-policy.md +0 -40
  281. package/skills/setup-freeflow/references/output-router-setup.md +0 -110
  282. package/skills/track-work/references/working-record-schema.md +0 -378
  283. package/skills/workflow/references/workflow-loop.md +0 -92
  284. /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
  285. /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("../../../skills/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) {