@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
@@ -1,17 +1,17 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { normalizeFreeflowConfig, normalizeLocalFreeflowConfig } from "../../../router/dist/index.js";
4
+ import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
5
+ import { isPiFlowHost } from "./runtime-identity.js";
5
6
  export const VALID_MODES = new Set(["conversation", "workflow", "strict-workflow"]);
6
7
  export const WORKFLOW_COMMANDS = [
7
8
  { command: "discuss", skill: "discuss" },
8
- { command: "discover", skill: "discuss" },
9
+ { command: "action-selection", skill: "action-selection" },
9
10
  { command: "track-work", skill: "track-work" },
10
11
  { command: "write-spec", skill: "write-spec" },
11
12
  { command: "review-artifact", skill: "review-artifact" },
12
13
  { command: "write-plan", skill: "write-plan" },
13
14
  { command: "execute-work", skill: "execute-work" },
14
- { command: "execute-plan", skill: "execute-work" },
15
15
  { command: "simplify-code", skill: "simplify-code" },
16
16
  { command: "migration-work", skill: "migration-work" },
17
17
  { command: "diagnose-failure", skill: "diagnose-failure" },
@@ -26,6 +26,7 @@ export const WORKFLOW_COMMANDS = [
26
26
  ];
27
27
  export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-skill"];
28
28
  export const FREEFLOW_MODEL_SKILL_NAMES = [
29
+ "action-selection",
29
30
  "bypass",
30
31
  "commit-work",
31
32
  "decision-gate",
@@ -52,54 +53,107 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
52
53
  "write-skill",
53
54
  "write-spec",
54
55
  ];
56
+ export const FREEFLOW_CAPABILITY_SKILL_NAMES = ["cognitive-routing", "context-virtualization", "conversation-history"];
55
57
  export function freeflowSkillPath(skillName) {
56
58
  return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
57
59
  }
58
- export function freeflowModelSkillPaths() {
59
- return FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
60
+ export function freeflowCapabilitySkillPath(skillName) {
61
+ return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
62
+ }
63
+ export function freeflowModelSkillPaths(capabilityState = undefined) {
64
+ const paths = FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
65
+ const capabilityStates = {
66
+ "cognitive-routing": capabilityState?.cognitiveRouting,
67
+ "context-virtualization": capabilityState?.contextVirtualization,
68
+ "conversation-history": capabilityState?.conversationHistory,
69
+ };
70
+ for (const skillName of FREEFLOW_CAPABILITY_SKILL_NAMES) {
71
+ if (capabilityStates[skillName]?.effective === true) {
72
+ paths.push(freeflowCapabilitySkillPath(skillName));
73
+ }
74
+ }
75
+ return paths;
60
76
  }
61
77
  const MODE_STATE_ENTRY = "freeflow-mode";
62
78
  const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
63
- const SESSION_CORE_KEYS = new Set(["enabled", "interactionContract", "skillsEnabled"]);
79
+ const SESSION_CORE_KEYS = new Set([
80
+ "enabled",
81
+ "interactionContract",
82
+ "skillsEnabled",
83
+ "contextVirtualization",
84
+ "conversationHistory",
85
+ ]);
64
86
  const RESET_MODE_ARGS = new Set(["reset"]);
65
- export const FREEFLOW_STATUS_TOOL_NAME = "freeflow_status";
66
- export const OUTPUT_ROUTER_TOOL_NAMES = ["freeflow_search", "freeflow_run", "freeflow_batch"];
87
+ export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
88
+ export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
89
+ export const COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-cognitive-routing-runtime-state";
67
90
  export const WORKFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-workflow-bootstrap";
91
+ export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-routing-bootstrap";
92
+ export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
68
93
  let runtimeContextCache = null;
69
94
  let currentModeOverride = null;
70
95
  let currentSessionOverrides = {};
71
- let lastRouterConfigWarningKey = null;
96
+ async function readPromptFile(url) {
97
+ try {
98
+ return await readFile(url, "utf8");
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
72
103
  async function loadRuntimeContext(capabilityState = undefined) {
104
+ const freeflowEnabled = capabilityState?.enabled === true;
73
105
  const interactionContractEnabled = capabilityState?.interactionContract?.effective === true;
74
106
  const skillsEnabled = capabilityState?.skills?.effective === true;
75
- const outputRouterEnabled = capabilityState?.outputRouter?.enabled === true;
76
- const [interactionContract, workflowSkill, outputRouterSkill] = await Promise.all([
107
+ const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
108
+ const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
109
+ const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
110
+ const [
111
+ corePrompt,
112
+ interactionContractPrompt,
113
+ skillsPrompt,
114
+ cognitiveRoutingPrompt,
115
+ contextVirtualizationPrompt,
116
+ conversationHistoryPrompt,
117
+ ] = await Promise.all([
118
+ freeflowEnabled
119
+ ? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
120
+ : Promise.resolve(null),
77
121
  interactionContractEnabled
78
- ? readFile(new URL("../../../runtime/interaction-contract.md", import.meta.url), "utf8")
122
+ ? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
79
123
  : Promise.resolve(null),
80
124
  skillsEnabled
81
- ? readFile(new URL("../../../skills/workflow/SKILL.md", import.meta.url), "utf8")
125
+ ? readPromptFile(new URL("../../../runtime/prompts/skills.md", import.meta.url))
126
+ : Promise.resolve(null),
127
+ cognitiveRoutingEnabled
128
+ ? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
82
129
  : Promise.resolve(null),
83
- outputRouterEnabled
84
- ? readFile(new URL("../../../capabilities/output-router/SKILL.md", import.meta.url), "utf8")
130
+ contextVirtualizationEnabled
131
+ ? readPromptFile(new URL("../../../runtime/prompts/context-virtualization.md", import.meta.url))
132
+ : Promise.resolve(null),
133
+ conversationHistoryEnabled
134
+ ? readPromptFile(new URL("../../../runtime/prompts/conversation-history.md", import.meta.url))
85
135
  : Promise.resolve(null),
86
136
  ]);
87
- return { interactionContract, workflowSkill, outputRouterSkill };
137
+ return {
138
+ corePrompt,
139
+ interactionContractPrompt,
140
+ skillsPrompt,
141
+ cognitiveRoutingPrompt,
142
+ contextVirtualizationPrompt,
143
+ conversationHistoryPrompt,
144
+ };
88
145
  }
89
146
  function runtimeContextCacheSatisfies(capabilityState) {
90
- if (!runtimeContextCache) {
91
- return false;
92
- }
93
- if (capabilityState?.interactionContract?.effective === true && !runtimeContextCache.interactionContract) {
94
- return false;
95
- }
96
- if (capabilityState?.skills?.effective === true && !runtimeContextCache.workflowSkill) {
97
- return false;
98
- }
99
- if (capabilityState?.outputRouter?.enabled === true && !runtimeContextCache.outputRouterSkill) {
100
- return false;
101
- }
102
- return true;
147
+ if (!runtimeContextCache) return false;
148
+ const expected = {
149
+ corePrompt: capabilityState?.enabled === true,
150
+ interactionContractPrompt: capabilityState?.interactionContract?.effective === true,
151
+ skillsPrompt: capabilityState?.skills?.effective === true,
152
+ cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
153
+ contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
154
+ conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
155
+ };
156
+ return Object.entries(expected).every(([key, required]) => !required || Boolean(runtimeContextCache[key]));
103
157
  }
104
158
  export async function refreshRuntimeContext(capabilityState = undefined) {
105
159
  runtimeContextCache = await loadRuntimeContext(capabilityState);
@@ -111,41 +165,32 @@ export async function getRuntimeContext(capabilityState = undefined) {
111
165
  }
112
166
  return refreshRuntimeContext(capabilityState);
113
167
  }
114
- function activeSessionEntries(sessionManager) {
115
- try {
116
- if (typeof sessionManager?.buildContextEntries === "function") {
117
- const entries = sessionManager.buildContextEntries();
118
- if (Array.isArray(entries)) {
119
- return entries;
120
- }
121
- }
122
- if (typeof sessionManager?.getEntries === "function") {
123
- const entries = sessionManager.getEntries();
124
- if (Array.isArray(entries)) {
125
- return entries;
126
- }
127
- }
128
- } catch {
129
- // A missing session snapshot should reload useful context rather than suppress it.
168
+ const BOOTSTRAP_COMPONENTS = Object.freeze({
169
+ workflow: "workflow",
170
+ cognitiveRouting: "cognitive-routing",
171
+ });
172
+ function bootstrapEntryComponents(entry) {
173
+ const isCustomMessage = entry?.role === "custom" || entry?.type === "custom_message" || entry?.type === "custom";
174
+ if (!isCustomMessage) return [];
175
+ if (entry.customType === FREEFLOW_BOOTSTRAP_MESSAGE_TYPE) {
176
+ if (Array.isArray(entry.details?.components)) return entry.details.components;
177
+ return [
178
+ ...(entry.content?.includes("<!-- freeflow-bootstrap:workflow -->") ? [BOOTSTRAP_COMPONENTS.workflow] : []),
179
+ ...(entry.content?.includes("<!-- freeflow-bootstrap:cognitive-routing -->")
180
+ ? [BOOTSTRAP_COMPONENTS.cognitiveRouting]
181
+ : []),
182
+ ];
183
+ }
184
+ if (entry.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE) {
185
+ return [BOOTSTRAP_COMPONENTS.workflow];
186
+ }
187
+ if (entry.customType === COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE) {
188
+ return [BOOTSTRAP_COMPONENTS.cognitiveRouting];
130
189
  }
131
190
  return [];
132
191
  }
133
- export function workflowBootstrapMessage(freeflowContext, capabilityState, sessionManager) {
134
- if (capabilityState?.skills?.effective !== true || !freeflowContext?.workflowSkill) {
135
- return undefined;
136
- }
137
- const alreadyLoaded = activeSessionEntries(sessionManager).some(
138
- (entry) => entry?.type === "custom_message" && entry?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
139
- );
140
- if (alreadyLoaded) {
141
- return undefined;
142
- }
143
- return {
144
- customType: WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
145
- content: `# Freeflow Workflow Bootstrap\n\n${freeflowContext.workflowSkill.trim()}`,
146
- display: false,
147
- details: { skill: "workflow", source: "first-turn-bootstrap" },
148
- };
192
+ export function filterBootstrapMessage(message) {
193
+ return bootstrapEntryComponents(message).length === 0 ? message : undefined;
149
194
  }
150
195
  function isRecord(value) {
151
196
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -157,6 +202,12 @@ function validateCoreConfigFields(value) {
157
202
  if (value.enabled !== undefined && typeof value.enabled !== "boolean") {
158
203
  return "enabled must be a boolean";
159
204
  }
205
+ if (value.contextVirtualization !== undefined && typeof value.contextVirtualization !== "boolean") {
206
+ return "contextVirtualization must be a boolean";
207
+ }
208
+ if (value.conversationHistory !== undefined && typeof value.conversationHistory !== "boolean") {
209
+ return "conversationHistory must be a boolean";
210
+ }
160
211
  if (value.interactionContract !== undefined && typeof value.interactionContract !== "boolean") {
161
212
  return "interactionContract must be a boolean";
162
213
  }
@@ -179,6 +230,7 @@ function validateFreeflowConfigShape(value) {
179
230
  if (!isRecord(value)) {
180
231
  return "config must be a JSON object";
181
232
  }
233
+ // Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
182
234
  const allowedKeys = new Set([
183
235
  "enabled",
184
236
  "defaultMode",
@@ -187,6 +239,9 @@ function validateFreeflowConfigShape(value) {
187
239
  "outputRouter",
188
240
  "observedRouting",
189
241
  "scriptTransform",
242
+ "cognitiveRouting",
243
+ "contextVirtualization",
244
+ "conversationHistory",
190
245
  ]);
191
246
  for (const key of Object.keys(value)) {
192
247
  if (!allowedKeys.has(key)) {
@@ -206,7 +261,16 @@ function validateFreeflowLocalConfigShape(value) {
206
261
  if (!isRecord(value)) {
207
262
  return "local config must be a JSON object";
208
263
  }
209
- const allowedKeys = new Set(["enabled", "defaultMode", "interactionContract", "skills", "processing"]);
264
+ const allowedKeys = new Set([
265
+ "enabled",
266
+ "defaultMode",
267
+ "interactionContract",
268
+ "skills",
269
+ "processing",
270
+ "cognitiveRouting",
271
+ "contextVirtualization",
272
+ "conversationHistory",
273
+ ]);
210
274
  for (const key of Object.keys(value)) {
211
275
  if (!allowedKeys.has(key)) {
212
276
  return `unsupported top-level local config key: ${key}`;
@@ -276,6 +340,8 @@ function resolveLayeredValue(repository, local, key, fallback) {
276
340
  function resolveCoreConfig(repository, local) {
277
341
  const enabled = resolveLayeredValue(repository, local, "enabled", true);
278
342
  const interactionContract = resolveLayeredValue(repository, local, "interactionContract", true);
343
+ const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
344
+ const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
279
345
  const defaultMode = resolveLayeredValue(repository, local, "defaultMode", "workflow");
280
346
  const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
281
347
  const localSkills = isRecord(local.skills) ? local.skills : {};
@@ -284,12 +350,16 @@ function resolveCoreConfig(repository, local) {
284
350
  config: {
285
351
  enabled: enabled.value,
286
352
  interactionContract: interactionContract.value,
353
+ contextVirtualization: contextVirtualization.value,
354
+ conversationHistory: conversationHistory.value,
287
355
  skills: { enabled: skillsEnabled.value },
288
356
  defaultMode: defaultMode.value,
289
357
  },
290
358
  sources: {
291
359
  enabled: enabled.source,
292
360
  interactionContract: interactionContract.source,
361
+ contextVirtualization: contextVirtualization.source,
362
+ conversationHistory: conversationHistory.source,
293
363
  skillsEnabled: skillsEnabled.source,
294
364
  defaultMode: defaultMode.source,
295
365
  },
@@ -310,18 +380,26 @@ function resolveSessionCoreConfig(layers) {
310
380
  const sources = layers.sources;
311
381
  const enabled = currentSessionOverrides.enabled;
312
382
  const interactionContract = currentSessionOverrides.interactionContract;
383
+ const contextVirtualization = currentSessionOverrides.contextVirtualization;
384
+ const conversationHistory = currentSessionOverrides.conversationHistory;
313
385
  const skillsEnabled = currentSessionOverrides.skillsEnabled;
314
386
  return {
315
387
  config: {
316
388
  enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
317
389
  interactionContract:
318
390
  typeof interactionContract === "boolean" ? interactionContract : configured.interactionContract,
391
+ contextVirtualization:
392
+ typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
393
+ conversationHistory:
394
+ typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
319
395
  skills: { enabled: typeof skillsEnabled === "boolean" ? skillsEnabled : configured.skills.enabled },
320
396
  defaultMode: configured.defaultMode,
321
397
  },
322
398
  sources: {
323
399
  enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
324
400
  interactionContract: typeof interactionContract === "boolean" ? "session" : sources.interactionContract,
401
+ contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
402
+ conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
325
403
  skillsEnabled: typeof skillsEnabled === "boolean" ? "session" : sources.skillsEnabled,
326
404
  defaultMode: sources.defaultMode,
327
405
  },
@@ -351,15 +429,60 @@ export async function readFreeflowConfigLayers(cwd) {
351
429
  parseError: blockingState?.parseError ?? null,
352
430
  };
353
431
  }
354
- export async function readCapabilityState(cwd) {
432
+ export async function readCapabilityState(cwd, host = undefined, extensionHost = undefined) {
355
433
  const layers = await readFreeflowConfigLayers(cwd);
356
- const parsed = layers.repository.valid ? layers.repository.parsed : {};
357
- const normalized = normalizeFreeflowConfig(parsed);
358
434
  const effectiveCore = resolveSessionCoreConfig(layers);
359
435
  const enabled = layers.configured && effectiveCore.config.enabled;
360
436
  const interactionContractConfigEnabled = effectiveCore.config.interactionContract;
361
437
  const skillsConfigEnabled = effectiveCore.config.skills.enabled;
362
- const outputRouterConfigEnabled = normalized.config.outputRouter.enabled;
438
+ const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
439
+ const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
440
+ const skillsEffective = enabled && skillsConfigEnabled;
441
+ const hostSupportsCognitiveRouting = isPiFlowHost(extensionHost);
442
+ const configuredCognitiveRouting = await resolveCognitiveRoutingState(
443
+ layers.repository.parsed,
444
+ layers.local.parsed,
445
+ hostSupportsCognitiveRouting ? host : undefined,
446
+ );
447
+ const disabledReason = enabled
448
+ ? skillsEffective
449
+ ? undefined
450
+ : { code: "disabled", message: "Skills are disabled" }
451
+ : { code: "disabled", message: "Freeflow is disabled" };
452
+ const childCapability = (configuredEnabled) => ({
453
+ enabled: configuredEnabled,
454
+ effective: skillsEffective && configuredEnabled,
455
+ ...(disabledReason ? { blockingReason: disabledReason } : {}),
456
+ });
457
+ const cognitiveRouting = enabled
458
+ ? skillsEffective
459
+ ? !hostSupportsCognitiveRouting && configuredCognitiveRouting.configValid
460
+ ? {
461
+ ...configuredCognitiveRouting,
462
+ effective: false,
463
+ blockingReason: {
464
+ code: "runtime_disabled",
465
+ message: "Cognitive Routing is disabled outside the PiFlow runtime",
466
+ },
467
+ }
468
+ : configuredCognitiveRouting
469
+ : {
470
+ ...configuredCognitiveRouting,
471
+ effective: false,
472
+ blockingReason: {
473
+ code: "disabled",
474
+ message: "Skills are disabled",
475
+ },
476
+ }
477
+ : {
478
+ ...configuredCognitiveRouting,
479
+ enabled: false,
480
+ effective: false,
481
+ blockingReason: {
482
+ code: "disabled",
483
+ message: "Freeflow is disabled",
484
+ },
485
+ };
363
486
  return {
364
487
  configured: layers.configured,
365
488
  repositoryConfigured: layers.repositoryConfigured,
@@ -385,63 +508,13 @@ export async function readCapabilityState(cwd) {
385
508
  enabled: skillsConfigEnabled,
386
509
  effective: enabled && skillsConfigEnabled,
387
510
  },
388
- outputRouter: {
389
- enabled: enabled && outputRouterConfigEnabled,
390
- configEnabled: outputRouterConfigEnabled,
391
- },
511
+ contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
512
+ conversationHistory: childCapability(conversationHistoryConfigEnabled),
513
+ hostSupportsCognitiveRouting,
514
+ cognitiveRouting,
392
515
  };
393
516
  }
394
517
  export const readRuntimeState = readCapabilityState;
395
- export async function readOutputRouterConfig(cwd) {
396
- const layers = await readFreeflowConfigLayers(cwd);
397
- const parsed = layers.repository.valid ? layers.repository.parsed : {};
398
- const localParsed = layers.local.valid ? layers.local.parsed : {};
399
- const normalized = normalizeFreeflowConfig(parsed);
400
- const local = normalizeLocalFreeflowConfig(localParsed);
401
- const freeflowEnabled = layers.configured && layers.coreConfig.enabled;
402
- const effectiveConfig = freeflowEnabled
403
- ? normalized.config
404
- : {
405
- ...normalized.config,
406
- outputRouter: { ...normalized.config.outputRouter, enabled: false },
407
- observedRouting: {
408
- ...normalized.config.observedRouting,
409
- enabled: false,
410
- },
411
- scriptTransform: {
412
- ...normalized.config.scriptTransform,
413
- enabled: false,
414
- },
415
- };
416
- const configWarnings = [...normalized.warnings];
417
- if (layers.repository.exists && !layers.repository.valid) {
418
- configWarnings.unshift(
419
- `.freeflow/config.json could not be parsed; Freeflow runtime is inactive. ${layers.repository.parseError ?? ""}`.trim(),
420
- );
421
- }
422
- if (layers.local.exists && !layers.local.valid) {
423
- configWarnings.unshift(
424
- `.freeflow/local.json could not be parsed; Freeflow runtime is inactive. ${layers.local.parseError ?? ""}`.trim(),
425
- );
426
- }
427
- return {
428
- config: effectiveConfig.outputRouter,
429
- freeflowConfig: effectiveConfig,
430
- localConfig: local.config,
431
- warnings: [...configWarnings, ...local.warnings],
432
- };
433
- }
434
- export function notifyRouterConfigWarnings(ctx, routerConfigResult) {
435
- if (!routerConfigResult.warnings.length) {
436
- return;
437
- }
438
- const key = routerConfigResult.warnings.join("\n");
439
- if (key === lastRouterConfigWarningKey) {
440
- return;
441
- }
442
- lastRouterConfigWarningKey = key;
443
- ctx.ui.notify(`Freeflow config warning: ${routerConfigResult.warnings.join(" ")}`, "warning");
444
- }
445
518
  export function restoreModeOverride(ctx) {
446
519
  currentModeOverride = null;
447
520
  currentSessionOverrides = {};
@@ -479,7 +552,13 @@ export async function readModeState(cwd) {
479
552
  effectiveMode: active ? resolvedMode : null,
480
553
  };
481
554
  }
482
- export function setModeStatus(ctx, modeState, capabilityState = undefined) {
555
+ export function setModeStatus(
556
+ ctx,
557
+ modeState,
558
+ capabilityState = undefined,
559
+ cognitiveRoutingRuntime = undefined,
560
+ options = {},
561
+ ) {
483
562
  if (capabilityState && !capabilityState.configured) {
484
563
  ctx.ui.setStatus("freeflow", capabilityState.configExists ? "freeflow: config error" : "freeflow: setup needed");
485
564
  return;
@@ -500,8 +579,39 @@ export function setModeStatus(ctx, modeState, capabilityState = undefined) {
500
579
  } else if (capabilityState?.configSources?.skillsEnabled === "session") {
501
580
  active.push("skills off (session)");
502
581
  }
503
- if (capabilityState?.outputRouter.enabled) {
504
- active.push("router");
582
+ const cognitiveRouting = capabilityState?.cognitiveRouting;
583
+ const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
584
+ const startupSelectionSuppressesCognitiveRouting =
585
+ ctx?.modelStateProvenance?.explicitModel === true || ctx?.modelStateProvenance?.explicitThinking === true;
586
+ if (cognitiveRoutingActive) {
587
+ const profile = cognitiveRoutingRuntime.activeProfile;
588
+ const control =
589
+ cognitiveRoutingRuntime.controlMode === "manual-standard" ||
590
+ cognitiveRoutingRuntime.controlMode === "manual-reasoning"
591
+ ? "manual hold"
592
+ : "automatic";
593
+ active.push(`${profile} · ${control}`);
594
+ } else if (cognitiveRouting?.enabled === true) {
595
+ if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
596
+ active.push("cognitive disabled · PiFlow only");
597
+ } else if (
598
+ cognitiveRouting.effective === true &&
599
+ cognitiveRoutingRuntime === undefined &&
600
+ options.cognitiveRoutingStartupPending === true &&
601
+ !startupSelectionSuppressesCognitiveRouting
602
+ ) {
603
+ const startupProfile = cognitiveRouting.sessionStart?.profile ?? "standard";
604
+ active.push(`${startupProfile} · pending`);
605
+ } else {
606
+ const reason =
607
+ cognitiveRouting?.effective === true
608
+ ? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
609
+ : (cognitiveRouting.blockingReason?.code ?? "unavailable");
610
+ active.push(`cognitive blocked · ${reason}`);
611
+ }
612
+ }
613
+ if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
614
+ active.push("context");
505
615
  }
506
616
  ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "idle"}`);
507
617
  }
@@ -521,156 +631,93 @@ export function skillPrompt(skill, args) {
521
631
  const trimmed = args?.trim();
522
632
  return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
523
633
  }
524
- function outputRouterModeGuidance(mode, skillsEnabled = true) {
525
- if (!skillsEnabled) {
526
- return "Freeflow Skills are disabled: no Freeflow workflow mode is active; apply only output-router evidence guidance.";
527
- }
528
- if (mode === "conversation") {
529
- return "conversation mode: keep routed-tool guidance soft; answer questions directly.";
530
- }
531
- if (mode === "strict-workflow") {
532
- return "strict-workflow mode: strongest guidance; prefer exact, recoverable routed evidence for risky work.";
533
- }
534
- return "workflow mode: prefer routed tools for exploration and likely-large command output.";
535
- }
536
- function outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
537
- const safetyNetText =
538
- routerConfigResult.config.postToolRouting === "off"
539
- ? ""
540
- : "\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.";
541
- return `## Loaded Output Router Skill
542
-
543
- Mode guidance: ${outputRouterModeGuidance(modeState.effectiveMode, capabilityState.skills.effective)}${safetyNetText}
544
-
545
- \`\`\`md
546
- ${freeflowContext.outputRouterSkill.trim()}
547
- \`\`\``;
548
- }
549
- function capabilityContext(capabilityState) {
550
- const sessionSuffix = (source) => (source === "session" ? " (session override)" : "");
551
- const interactionContract = `${capabilityState.interactionContract.effective ? "enabled" : "disabled"}${sessionSuffix(capabilityState.configSources.interactionContract)}`;
552
- const skills = `${capabilityState.skills.effective ? "enabled" : "disabled"}${sessionSuffix(capabilityState.configSources.skillsEnabled)}`;
553
- const outputRouter = capabilityState.outputRouter.enabled ? "enabled" : "disabled";
554
- return `## Freeflow Capabilities
555
-
556
- - Interaction contract: ${interactionContract}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
557
- - Skills: ${skills}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
558
- - Output router: ${outputRouter}. Configure with \`/freeflow settings\` or \`/output-router\`; inspect with \`/output-router status\`.
559
-
560
- Disabled capabilities are named only for status/config awareness. Capability-specific instructions and tools are active only while that capability is enabled.`;
561
- }
562
- function hasModelFacingCapability(capabilityState) {
563
- return (
564
- capabilityState.interactionContract.effective ||
565
- capabilityState.skills.effective ||
566
- capabilityState.outputRouter.enabled
634
+ function publicCognitiveRoutingControl(controlMode) {
635
+ if (controlMode === "automatic") return "automatic";
636
+ if (controlMode === "manual-standard" || controlMode === "manual-reasoning") return "manual";
637
+ return "unavailable";
638
+ }
639
+ function publicCognitiveRoutingProfile(activeProfile, effective) {
640
+ if (effective !== true) return "unavailable";
641
+ return activeProfile === "standard" || activeProfile === "reasoning" ? activeProfile : "unavailable";
642
+ }
643
+ function publicCapabilityStatus(capability) {
644
+ if (capability?.effective === true) return "active";
645
+ if (!capability) return "unavailable";
646
+ const blockingCode = capability.blockingReason?.code;
647
+ if (blockingCode && blockingCode !== "disabled") return "unavailable";
648
+ return "inactive";
649
+ }
650
+ export function freeflowRuntimeStateMessage(modeState, capabilityState, cognitiveRoutingRuntime = undefined) {
651
+ const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
652
+ const profile = publicCognitiveRoutingProfile(
653
+ cognitiveRoutingRuntime?.activeProfile,
654
+ cognitiveRoutingEffective && cognitiveRoutingRuntime?.effective === true,
567
655
  );
656
+ const control =
657
+ profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
658
+ const defaultMode = modeState?.defaultMode ?? "workflow";
659
+ const activeMode = modeState?.effectiveMode ?? "inactive";
660
+ return {
661
+ role: "custom",
662
+ customType: FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE,
663
+ content: [
664
+ "# Freeflow Runtime State",
665
+ "",
666
+ "This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
667
+ "",
668
+ `Default mode: \`${defaultMode}\``,
669
+ `Active mode: \`${activeMode}\``,
670
+ "",
671
+ "Capabilities:",
672
+ `- Interaction Contract: ${publicCapabilityStatus(capabilityState?.interactionContract)}`,
673
+ `- Skills: ${publicCapabilityStatus(capabilityState?.skills)}`,
674
+ `- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
675
+ `- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
676
+ `- Cognitive Routing: ${publicCapabilityStatus(capabilityState?.cognitiveRouting)}`,
677
+ "",
678
+ "Cognitive Routing:",
679
+ `- Control: \`${control}\``,
680
+ `- Profile: \`${profile}\``,
681
+ ].join("\n"),
682
+ display: false,
683
+ details: { source: "provider-request-runtime-state" },
684
+ };
568
685
  }
569
- function modeOverlayContext(mode) {
570
- if (mode === "conversation") {
571
- return `
572
-
573
- ## Conversation Mode Boundary
574
-
575
- Conversation mode is active and read-only.
576
-
577
- Do not call write, edit, or mutating tools. Do not create, delete, commit, push, or change repository, system, external, or durable state.
578
-
579
- 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.`;
580
- }
581
- if (mode === "strict-workflow") {
582
- return `
583
-
584
- ## Strict Workflow Overlay
585
-
586
- Strict Workflow is active. Use the adaptive Workflow, but increase decision, evidence, verification, and checkpoint pressure at high-risk or hard-to-reverse boundaries.
587
-
588
- For work affecting security, privacy, billing, data loss, migrations, public interfaces, compatibility, deployment, or architecture:
589
-
590
- - stop for any user-owned choice or source conflict;
591
- - inspect the relevant risk surface before crossing the boundary;
592
- - select only artifacts, checkpoints, and independent review that materially reduce risk;
593
- - verify at the affected boundary before claiming success.
594
-
595
- 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.`;
596
- }
597
- return "";
598
- }
599
- function activeModeContext(modeState) {
600
- return `## Freeflow Mode State
601
-
602
- Repository default mode: \`${modeState.repositoryDefaultMode}\` (${modeState.repositoryDefaultModeSource}).
603
- Personal default override: \`${modeState.personalDefaultMode ?? "none"}\`.
604
- Configured default mode: \`${modeState.defaultMode}\` (${modeSourceLabel(modeState.defaultModeSource)}).
605
- Session mode override: \`${modeState.sessionMode ?? "none"}\`.
606
- Resolved mode: \`${modeState.resolvedMode}\`.
607
- Effective Freeflow mode: \`${modeState.effectiveMode}\`.
608
-
609
- Mode behavior:
610
- - \`conversation\`: answer, discuss, critique, and inspect read-only; require a mode change before mutating state.
611
- - \`workflow\`: use the adaptive workflow for consequential or mutating work.
612
- - \`strict-workflow\`: use the same workflow with stronger decision, evidence, and checkpoint pressure at high-risk or hard-to-reverse boundaries.
613
-
614
- Task type, risk classification, and direct skill calls do not change mode. Recommend another mode when useful; the user decides.
615
- 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)}`;
616
- }
617
- function inactiveModeContext(modeState) {
618
- return `## Freeflow Mode State
619
-
620
- Repository default mode: \`${modeState.repositoryDefaultMode}\` (${modeState.repositoryDefaultModeSource}).
621
- Personal default override: \`${modeState.personalDefaultMode ?? "none"}\`.
622
- Configured default mode: \`${modeState.defaultMode}\` (${modeSourceLabel(modeState.defaultModeSource)}).
623
- Session mode override: \`${modeState.sessionMode ?? "none"}\`.
624
- Resolved mode: \`${modeState.resolvedMode}\` (inactive because Skills are disabled).
625
- Effective Freeflow mode: \`none\`.
626
-
627
- Freeflow workflow modes are dormant until Skills are enabled with \`/freeflow settings\`.`;
628
- }
629
- function controlPlaneContext(modeState, capabilityState) {
630
- return `# Freeflow Control Plane
631
-
632
- Freeflow is enabled for this repo, but no model-facing capabilities are enabled.
633
- These lines are status/config awareness only; do not apply Freeflow workflow or output-router behavior.
634
-
635
- ${inactiveModeContext(modeState)}
636
-
637
- ${capabilityContext(capabilityState)}
638
-
639
- 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.`;
640
- }
641
- export function runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
642
- if (!capabilityState.configured) {
686
+ export function withoutFreeflowRuntimeState(messages) {
687
+ return (Array.isArray(messages) ? messages : []).filter(
688
+ (message) =>
689
+ message?.customType !== FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
690
+ message?.customType !== COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
691
+ );
692
+ }
693
+ export function withFreeflowRuntimeState(messages, modeState, capabilityState, cognitiveRoutingRuntime = undefined) {
694
+ return [
695
+ ...withoutFreeflowRuntimeState(messages),
696
+ freeflowRuntimeStateMessage(modeState, capabilityState, cognitiveRoutingRuntime),
697
+ ];
698
+ }
699
+ export function runtimeContext(freeflowContext, capabilityState) {
700
+ if (capabilityState?.configured !== true || capabilityState?.enabled !== true || !freeflowContext?.corePrompt) {
643
701
  return "";
644
702
  }
645
- if (!capabilityState.enabled) {
646
- return `# Freeflow Disabled
647
-
648
- 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\`.
649
-
650
- These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.`;
651
- }
652
- if (!hasModelFacingCapability(capabilityState)) {
653
- return controlPlaneContext(modeState, capabilityState);
654
- }
655
- const modeText = capabilityState.skills.effective ? activeModeContext(modeState) : inactiveModeContext(modeState);
656
- const interactionContractText = capabilityState.interactionContract.effective
657
- ? `\n\n${freeflowContext.interactionContract.trim()}`
658
- : "";
659
- const routerText =
660
- capabilityState.outputRouter.enabled && routerConfigResult.config.enabled
661
- ? `\n\n${outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState)}`
662
- : "";
663
- return `# Freeflow Runtime Context
664
-
665
- Freeflow Pi extension loaded this before the agent turn.
666
- Runtime delivery: confirmed for this Pi \`before_agent_start\` invocation.
667
- These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.
668
-
669
- ${modeText}
670
-
671
- ${capabilityContext(capabilityState)}${interactionContractText}${routerText}
672
-
673
- 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.`;
703
+ const blocks = [];
704
+ if (freeflowContext?.corePrompt) blocks.push(freeflowContext.corePrompt.trim());
705
+ if (capabilityState.interactionContract?.effective === true && freeflowContext?.interactionContractPrompt) {
706
+ blocks.push(freeflowContext.interactionContractPrompt.trim());
707
+ }
708
+ if (capabilityState.skills?.effective === true && freeflowContext?.skillsPrompt) {
709
+ blocks.push(freeflowContext.skillsPrompt.trim());
710
+ }
711
+ if (capabilityState.cognitiveRouting?.effective === true && freeflowContext?.cognitiveRoutingPrompt) {
712
+ blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
713
+ }
714
+ if (capabilityState.contextVirtualization?.effective === true && freeflowContext?.contextVirtualizationPrompt) {
715
+ blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
716
+ }
717
+ if (capabilityState.conversationHistory?.effective === true && freeflowContext?.conversationHistoryPrompt) {
718
+ blocks.push(freeflowContext.conversationHistoryPrompt.trim());
719
+ }
720
+ return blocks.filter(Boolean).join("\n\n");
674
721
  }
675
722
  export async function setSessionCoreOverride(key, value, ctx, pi) {
676
723
  if (!SESSION_CORE_KEYS.has(key)) {
@@ -695,7 +742,7 @@ export async function setSessionCoreOverride(key, value, ctx, pi) {
695
742
  changed: true,
696
743
  reloadRequired: key === "enabled" || key === "skillsEnabled",
697
744
  sessionOverrides: { ...currentSessionOverrides },
698
- capabilityState: await readCapabilityState(ctx.cwd),
745
+ capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
699
746
  };
700
747
  }
701
748
  export async function resetSessionOverrides(ctx, pi) {
@@ -728,7 +775,7 @@ export async function setSessionMode(mode, ctx, pi) {
728
775
  }
729
776
  export async function handleModeCommand(args, ctx, pi) {
730
777
  const arg = args?.trim();
731
- const capabilityState = await readCapabilityState(ctx.cwd);
778
+ const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
732
779
  const inactiveModeState = await readModeState(ctx.cwd);
733
780
  if (!capabilityState.configured) {
734
781
  setModeStatus(ctx, inactiveModeState, capabilityState);