@hassangameryt/freeflow 0.2.0 → 0.4.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 (312) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +4 -4
  3. package/{plugins/freeflow/.claude-plugin → .claude-plugin}/plugin.json +5 -2
  4. package/{plugins/freeflow/.codex-plugin → .codex-plugin}/plugin.json +8 -9
  5. package/README.md +194 -127
  6. package/assets/feedback-loop.png +0 -0
  7. package/assets/freeflow-plugin-icon.png +0 -0
  8. package/assets/freeflow_workflow_map.png +0 -0
  9. package/assets/workflow.png +0 -0
  10. package/command-surface.json +129 -0
  11. package/hooks/freeflow-runtime-context.mjs +419 -0
  12. package/hooks/tests/check-runtime-context-hook.sh +223 -0
  13. package/package.json +41 -22
  14. package/pi-extension/dist/index.js +269 -0
  15. package/pi-extension/dist/integrations/mcp-config.js +29 -0
  16. package/pi-extension/dist/output-router/host-producer-identification.js +232 -0
  17. package/pi-extension/dist/output-router/native-safety-net.js +216 -0
  18. package/pi-extension/dist/output-router/observed-tool-routing.js +122 -0
  19. package/pi-extension/dist/output-router/renderers.js +1023 -0
  20. package/pi-extension/dist/output-router/router-tools.js +554 -0
  21. package/pi-extension/dist/output-router/schemas.js +383 -0
  22. package/pi-extension/dist/output-router/status.js +744 -0
  23. package/pi-extension/dist/output-router/utils.js +502 -0
  24. package/pi-extension/dist/runtime/runtime-context.js +798 -0
  25. package/pi-extension/dist/settings/settings-tui.js +314 -0
  26. package/pi-extension/dist/settings/settings-ui.js +1487 -0
  27. package/pi-extension/freeflow/index.js +1 -0
  28. package/pi-extension/src/index.ts +295 -0
  29. package/pi-extension/src/integrations/mcp-config.ts +32 -0
  30. package/pi-extension/src/output-router/host-producer-identification.ts +256 -0
  31. package/pi-extension/src/output-router/native-safety-net.ts +248 -0
  32. package/pi-extension/src/output-router/observed-tool-routing.ts +134 -0
  33. package/pi-extension/src/output-router/renderers.ts +1108 -0
  34. package/pi-extension/src/output-router/router-tools.ts +579 -0
  35. package/pi-extension/src/output-router/schemas.ts +387 -0
  36. package/pi-extension/src/output-router/status.ts +791 -0
  37. package/pi-extension/src/output-router/utils.ts +554 -0
  38. package/pi-extension/src/runtime/runtime-context.ts +895 -0
  39. package/pi-extension/src/settings/settings-tui.ts +408 -0
  40. package/pi-extension/src/settings/settings-ui.ts +1730 -0
  41. package/pi-extension/tests/integration/pi-extension.test.js +4018 -0
  42. package/pi-extension/tests/output-router/observed-producers.test.js +132 -0
  43. package/pi-extension/tests/output-router/search.test.js +722 -0
  44. package/pi-extension/tests/settings/settings-tui.test.js +243 -0
  45. package/pi-extension/tsconfig.json +16 -0
  46. package/{plugins/freeflow/router/dist → router/dist/benchmarks}/benchmark-harness.d.ts +16 -13
  47. package/router/dist/benchmarks/benchmark-harness.js +92 -0
  48. package/router/dist/benchmarks/benchmarks.d.ts +109 -0
  49. package/router/dist/benchmarks/benchmarks.js +979 -0
  50. package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +95 -0
  51. package/router/dist/benchmarks/codex-qa-benchmarks.js +500 -0
  52. package/router/dist/benchmarks/command-benchmarks.d.ts +143 -0
  53. package/router/dist/benchmarks/command-benchmarks.js +698 -0
  54. package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +82 -0
  55. package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +773 -0
  56. package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +132 -0
  57. package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +1380 -0
  58. package/router/dist/benchmarks/context-saving-baseline.d.ts +60 -0
  59. package/router/dist/benchmarks/context-saving-baseline.js +470 -0
  60. package/router/dist/benchmarks/index-benchmarks.d.ts +103 -0
  61. package/router/dist/benchmarks/index-benchmarks.js +862 -0
  62. package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +101 -0
  63. package/router/dist/benchmarks/storage-policy-benchmarks.js +618 -0
  64. package/router/dist/benchmarks/vault-index-benchmarks.d.ts +56 -0
  65. package/router/dist/benchmarks/vault-index-benchmarks.js +322 -0
  66. package/router/dist/config/config.d.ts +103 -0
  67. package/router/dist/config/config.js +632 -0
  68. package/{plugins/freeflow/router/dist → router/dist/config}/router-contract.d.ts +2 -2
  69. package/router/dist/config/router-contract.js +54 -0
  70. package/{plugins/freeflow/router/dist → router/dist/config}/schema.d.ts +19 -10
  71. package/router/dist/config/schema.js +648 -0
  72. package/router/dist/config/types.d.ts +573 -0
  73. package/router/dist/config/types.js +41 -0
  74. package/router/dist/evidence/bounded-evidence.d.ts +40 -0
  75. package/router/dist/evidence/bounded-evidence.js +323 -0
  76. package/router/dist/evidence/evidence-range-selector.d.ts +24 -0
  77. package/router/dist/evidence/evidence-range-selector.js +232 -0
  78. package/router/dist/evidence/evidence-search.d.ts +27 -0
  79. package/router/dist/evidence/evidence-search.js +490 -0
  80. package/{plugins/freeflow/router/dist → router/dist/evidence}/evidence.d.ts +18 -18
  81. package/router/dist/evidence/evidence.js +200 -0
  82. package/router/dist/evidence/failure-contracts.d.ts +37 -0
  83. package/router/dist/evidence/failure-contracts.js +166 -0
  84. package/router/dist/evidence/line-ranges.d.ts +24 -0
  85. package/router/dist/evidence/line-ranges.js +22 -0
  86. package/router/dist/experiments/local-index.d.ts +64 -0
  87. package/router/dist/experiments/local-index.js +581 -0
  88. package/router/dist/index.d.ts +30 -0
  89. package/router/dist/index.js +32 -0
  90. package/router/dist/local/local-traversal.d.ts +18 -0
  91. package/router/dist/local/local-traversal.js +334 -0
  92. package/router/dist/processing/engine.d.ts +132 -0
  93. package/router/dist/processing/engine.js +533 -0
  94. package/router/dist/processing/reducers.d.ts +280 -0
  95. package/router/dist/processing/reducers.js +1673 -0
  96. package/router/dist/processing/renderers.d.ts +31 -0
  97. package/router/dist/processing/renderers.js +195 -0
  98. package/router/dist/processing/scripts.d.ts +91 -0
  99. package/router/dist/processing/scripts.js +386 -0
  100. package/{plugins/freeflow/router/dist → router/dist/repo}/repo-traversal.d.ts +9 -9
  101. package/router/dist/repo/repo-traversal.js +245 -0
  102. package/router/dist/routing/observed-reducers.d.ts +41 -0
  103. package/router/dist/routing/observed-reducers.js +661 -0
  104. package/router/dist/routing/observed-routing.d.ts +26 -0
  105. package/router/dist/routing/observed-routing.js +378 -0
  106. package/router/dist/routing/parsers.d.ts +16 -0
  107. package/router/dist/routing/parsers.js +521 -0
  108. package/router/dist/routing/run-filters.d.ts +60 -0
  109. package/router/dist/routing/run-filters.js +238 -0
  110. package/router/dist/routing/run-reducers.d.ts +49 -0
  111. package/router/dist/routing/run-reducers.js +122 -0
  112. package/router/dist/sandbox/adapter-roots.d.ts +46 -0
  113. package/router/dist/sandbox/adapter-roots.js +66 -0
  114. package/router/dist/sandbox/eryx-python-adapter.d.ts +13 -0
  115. package/router/dist/sandbox/eryx-python-adapter.js +868 -0
  116. package/router/dist/sandbox/jq-wasm-adapter.d.ts +9 -0
  117. package/router/dist/sandbox/jq-wasm-adapter.js +429 -0
  118. package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +13 -0
  119. package/router/dist/sandbox/quickjs-wasi-adapter.js +384 -0
  120. package/router/dist/sandbox/script-sandbox.d.ts +134 -0
  121. package/router/dist/sandbox/script-sandbox.js +337 -0
  122. package/router/dist/setup/script-transform-adapters.d.ts +32 -0
  123. package/router/dist/setup/script-transform-adapters.js +278 -0
  124. package/router/dist/tools/batch.d.ts +33 -0
  125. package/router/dist/tools/batch.js +586 -0
  126. package/router/dist/tools/run.d.ts +62 -0
  127. package/router/dist/tools/run.js +1304 -0
  128. package/router/dist/tools/search.d.ts +66 -0
  129. package/router/dist/tools/search.js +1364 -0
  130. package/router/dist/transform/engine.d.ts +168 -0
  131. package/router/dist/transform/engine.js +2072 -0
  132. package/router/dist/vault/vault-index.d.ts +125 -0
  133. package/router/dist/vault/vault-index.js +416 -0
  134. package/router/dist/vault/vault.d.ts +138 -0
  135. package/router/dist/vault/vault.js +630 -0
  136. package/runtime/interaction-contract.md +16 -0
  137. package/skills/bypass/SKILL.md +82 -0
  138. package/skills/commit-work/SKILL.md +106 -0
  139. package/skills/commit-work/references/staging-decisions.md +73 -0
  140. package/skills/decision-gate/SKILL.md +48 -0
  141. package/skills/design-for-depth/SKILL.md +106 -0
  142. package/skills/design-for-depth/references/design-pressure-signals.md +314 -0
  143. package/skills/design-for-depth/references/interface-design-loop.md +156 -0
  144. package/skills/design-for-depth/references/software-design-philosophy.md +248 -0
  145. package/skills/diagnose-failure/SKILL.md +105 -0
  146. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +36 -0
  147. package/skills/diagnose-failure/references/flaky-and-performance.md +43 -0
  148. package/skills/discuss/SKILL.md +121 -0
  149. package/skills/discuss/references/checkpoints.md +66 -0
  150. package/skills/evaluate-skill/SKILL.md +105 -0
  151. package/skills/evaluate-skill/references/definition-schema.md +345 -0
  152. package/skills/evaluate-skill/references/evaluation-design.md +86 -0
  153. package/skills/evaluate-skill/references/execution-and-evidence.md +85 -0
  154. package/skills/evaluate-skill/references/review-and-revision.md +51 -0
  155. package/skills/evaluate-skill/scripts/lib/definitions.mjs +296 -0
  156. package/skills/evaluate-skill/scripts/lib/evidence.mjs +46 -0
  157. package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +60 -0
  158. package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +148 -0
  159. package/skills/evaluate-skill/scripts/lib/grade-support.mjs +126 -0
  160. package/skills/evaluate-skill/scripts/lib/grade-workspace.mjs +192 -0
  161. package/skills/evaluate-skill/scripts/lib/grade.mjs +56 -0
  162. package/skills/evaluate-skill/scripts/lib/pi.mjs +489 -0
  163. package/skills/evaluate-skill/scripts/lib/process.mjs +79 -0
  164. package/skills/evaluate-skill/scripts/lib/rpc.mjs +444 -0
  165. package/skills/evaluate-skill/scripts/lib/runner.mjs +346 -0
  166. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +409 -0
  167. package/skills/evaluate-skill/scripts/lib/view.mjs +337 -0
  168. package/skills/evaluate-skill/scripts/pi-guard.mjs +164 -0
  169. package/skills/evaluate-skill/scripts/skill-eval.mjs +101 -0
  170. package/skills/execute-work/SKILL.md +99 -0
  171. package/skills/execute-work/references/code-practices.md +78 -0
  172. package/skills/execute-work/references/execution-loop.md +77 -0
  173. package/skills/finish-branch/SKILL.md +117 -0
  174. package/skills/finish-branch/references/integration-options.md +80 -0
  175. package/skills/handoff/SKILL.md +92 -0
  176. package/skills/handoff/references/templates.md +141 -0
  177. package/skills/launch-work/SKILL.md +116 -0
  178. package/skills/launch-work/references/launch-readiness.md +85 -0
  179. package/skills/migration-work/SKILL.md +115 -0
  180. package/skills/migration-work/references/migration-lifecycle.md +82 -0
  181. package/skills/mode-contract/SKILL.md +82 -0
  182. package/skills/output-router/SKILL.md +206 -0
  183. package/skills/output-router/references/safety-policy.md +40 -0
  184. package/skills/release-work/SKILL.md +118 -0
  185. package/skills/release-work/references/release-evidence.md +78 -0
  186. package/skills/review-artifact/SKILL.md +126 -0
  187. package/skills/review-artifact/references/reviewer-prompt.md +148 -0
  188. package/skills/review-work/SKILL.md +126 -0
  189. package/skills/review-work/references/reviewer-prompt.md +134 -0
  190. package/skills/review-work/references/security-risk-lens.md +67 -0
  191. package/skills/setup-freeflow/SKILL.md +98 -0
  192. package/skills/setup-freeflow/references/activation-contract.md +120 -0
  193. package/skills/setup-freeflow/references/host-setup.md +72 -0
  194. package/skills/setup-freeflow/references/output-router-setup.md +110 -0
  195. package/skills/simplify-code/SKILL.md +80 -0
  196. package/skills/simplify-code/references/simplification-patterns.md +70 -0
  197. package/skills/tdd/SKILL.md +96 -0
  198. package/skills/tdd/references/test-design.md +96 -0
  199. package/skills/track-work/SKILL.md +84 -0
  200. package/skills/track-work/references/working-record-schema.md +378 -0
  201. package/skills/verify-work/SKILL.md +85 -0
  202. package/skills/verify-work/references/browser-runtime-evidence.md +55 -0
  203. package/skills/verify-work/references/integration-evidence.md +51 -0
  204. package/skills/verify-work/references/performance-evidence.md +57 -0
  205. package/skills/workflow/SKILL.md +91 -0
  206. package/skills/workflow/references/domain-skill-composition.md +57 -0
  207. package/skills/workflow/references/workflow-loop.md +92 -0
  208. package/skills/write-plan/SKILL.md +123 -0
  209. package/skills/write-plan/references/plan-shapes.md +156 -0
  210. package/skills/write-skill/SKILL.md +119 -0
  211. package/skills/write-skill/references/activation-boundaries.md +62 -0
  212. package/skills/write-skill/references/agent-first-instructions.md +87 -0
  213. package/skills/write-skill/references/progressive-disclosure.md +63 -0
  214. package/skills/write-skill/scripts/lib/skill-author.mjs +653 -0
  215. package/skills/write-skill/scripts/skill-author.mjs +104 -0
  216. package/skills/write-spec/SKILL.md +104 -0
  217. package/skills/write-spec/references/artifact-standards.md +86 -0
  218. package/skills/write-spec/references/decision-records.md +77 -0
  219. package/skills/write-spec/references/spec-shapes.md +128 -0
  220. package/plugins/freeflow/command-surface.json +0 -77
  221. package/plugins/freeflow/docs/README.md +0 -40
  222. package/plugins/freeflow/docs/adr/0001-three-modes.md +0 -27
  223. package/plugins/freeflow/docs/adr/0002-evals-before-hooks.md +0 -17
  224. package/plugins/freeflow/docs/adr/0003-release-boundary.md +0 -21
  225. package/plugins/freeflow/docs/adr/0004-research-replaces-shallow-discovery-skills.md +0 -26
  226. package/plugins/freeflow/docs/adr/README.md +0 -8
  227. package/plugins/freeflow/docs/architecture.md +0 -86
  228. package/plugins/freeflow/docs/output-router.md +0 -212
  229. package/plugins/freeflow/docs/release-evidence.md +0 -69
  230. package/plugins/freeflow/docs/skills.md +0 -43
  231. package/plugins/freeflow/docs/workflow.md +0 -57
  232. package/plugins/freeflow/hooks/freeflow-runtime-context.mjs +0 -257
  233. package/plugins/freeflow/pi-extension/index.js +0 -1176
  234. package/plugins/freeflow/router/dist/benchmark-harness.js +0 -92
  235. package/plugins/freeflow/router/dist/benchmarks.d.ts +0 -102
  236. package/plugins/freeflow/router/dist/benchmarks.js +0 -880
  237. package/plugins/freeflow/router/dist/bounded-evidence.d.ts +0 -40
  238. package/plugins/freeflow/router/dist/bounded-evidence.js +0 -310
  239. package/plugins/freeflow/router/dist/codex-qa-benchmarks.d.ts +0 -91
  240. package/plugins/freeflow/router/dist/codex-qa-benchmarks.js +0 -461
  241. package/plugins/freeflow/router/dist/command-benchmarks.d.ts +0 -128
  242. package/plugins/freeflow/router/dist/command-benchmarks.js +0 -652
  243. package/plugins/freeflow/router/dist/config.d.ts +0 -22
  244. package/plugins/freeflow/router/dist/config.js +0 -114
  245. package/plugins/freeflow/router/dist/evidence-range-selector.d.ts +0 -22
  246. package/plugins/freeflow/router/dist/evidence-range-selector.js +0 -180
  247. package/plugins/freeflow/router/dist/evidence-search.d.ts +0 -25
  248. package/plugins/freeflow/router/dist/evidence-search.js +0 -450
  249. package/plugins/freeflow/router/dist/evidence.js +0 -196
  250. package/plugins/freeflow/router/dist/experimental-local-index.d.ts +0 -1
  251. package/plugins/freeflow/router/dist/experimental-local-index.js +0 -1
  252. package/plugins/freeflow/router/dist/experiments/local-index.d.ts +0 -58
  253. package/plugins/freeflow/router/dist/experiments/local-index.js +0 -562
  254. package/plugins/freeflow/router/dist/index-benchmarks.d.ts +0 -84
  255. package/plugins/freeflow/router/dist/index-benchmarks.js +0 -458
  256. package/plugins/freeflow/router/dist/index.d.ts +0 -12
  257. package/plugins/freeflow/router/dist/index.js +0 -12
  258. package/plugins/freeflow/router/dist/line-ranges.d.ts +0 -22
  259. package/plugins/freeflow/router/dist/line-ranges.js +0 -22
  260. package/plugins/freeflow/router/dist/parsers.d.ts +0 -16
  261. package/plugins/freeflow/router/dist/parsers.js +0 -473
  262. package/plugins/freeflow/router/dist/repo-traversal.js +0 -242
  263. package/plugins/freeflow/router/dist/retrieve.d.ts +0 -33
  264. package/plugins/freeflow/router/dist/retrieve.js +0 -855
  265. package/plugins/freeflow/router/dist/router-contract.js +0 -54
  266. package/plugins/freeflow/router/dist/run.d.ts +0 -26
  267. package/plugins/freeflow/router/dist/run.js +0 -356
  268. package/plugins/freeflow/router/dist/schema.js +0 -354
  269. package/plugins/freeflow/router/dist/types.d.ts +0 -234
  270. package/plugins/freeflow/router/dist/types.js +0 -9
  271. package/plugins/freeflow/router/dist/vault.d.ts +0 -80
  272. package/plugins/freeflow/router/dist/vault.js +0 -484
  273. package/plugins/freeflow/skills/bypass/SKILL.md +0 -68
  274. package/plugins/freeflow/skills/commit-work/SKILL.md +0 -98
  275. package/plugins/freeflow/skills/commit-work/references/staging-decisions.md +0 -51
  276. package/plugins/freeflow/skills/diagnose-failure/SKILL.md +0 -95
  277. package/plugins/freeflow/skills/diagnose-failure/references/feedback-loop-catalog.md +0 -25
  278. package/plugins/freeflow/skills/diagnose-failure/references/flaky-and-performance.md +0 -31
  279. package/plugins/freeflow/skills/evaluate-skill/SKILL.md +0 -96
  280. package/plugins/freeflow/skills/evaluate-skill/references/eval-patterns.md +0 -41
  281. package/plugins/freeflow/skills/evaluate-skill/references/grading-priority.md +0 -33
  282. package/plugins/freeflow/skills/execute-plan/SKILL.md +0 -132
  283. package/plugins/freeflow/skills/execute-plan/references/execution-map.md +0 -122
  284. package/plugins/freeflow/skills/handoff/SKILL.md +0 -66
  285. package/plugins/freeflow/skills/handoff/references/templates.md +0 -64
  286. package/plugins/freeflow/skills/interview-gate/SKILL.md +0 -90
  287. package/plugins/freeflow/skills/mode-contract/SKILL.md +0 -79
  288. package/plugins/freeflow/skills/output-router/SKILL.md +0 -69
  289. package/plugins/freeflow/skills/output-router/references/safety-policy.md +0 -33
  290. package/plugins/freeflow/skills/research/ARTIFACT-DESTINATIONS.md +0 -58
  291. package/plugins/freeflow/skills/research/CHECKPOINTS.md +0 -74
  292. package/plugins/freeflow/skills/research/LANGUAGE.md +0 -61
  293. package/plugins/freeflow/skills/research/SKILL.md +0 -128
  294. package/plugins/freeflow/skills/review-artifact/SKILL.md +0 -115
  295. package/plugins/freeflow/skills/review-artifact/references/reviewer-prompt.md +0 -56
  296. package/plugins/freeflow/skills/review-work/SKILL.md +0 -96
  297. package/plugins/freeflow/skills/review-work/references/reviewer-prompt.md +0 -97
  298. package/plugins/freeflow/skills/setup-freeflow/SKILL.md +0 -94
  299. package/plugins/freeflow/skills/setup-freeflow/references/activation-contract.md +0 -99
  300. package/plugins/freeflow/skills/setup-freeflow/references/host-setup.md +0 -35
  301. package/plugins/freeflow/skills/setup-freeflow/references/output-router-setup.md +0 -52
  302. package/plugins/freeflow/skills/verify-work/SKILL.md +0 -62
  303. package/plugins/freeflow/skills/workflow/SKILL.md +0 -95
  304. package/plugins/freeflow/skills/workflow/references/workflow-map.md +0 -102
  305. package/plugins/freeflow/skills/write-plan/SKILL.md +0 -88
  306. package/plugins/freeflow/skills/write-plan/references/plan-shapes.md +0 -70
  307. package/plugins/freeflow/skills/write-skill/SKILL.md +0 -88
  308. package/plugins/freeflow/skills/write-spec/SKILL.md +0 -90
  309. package/plugins/freeflow/skills/write-spec/references/artifact-standards.md +0 -67
  310. package/plugins/freeflow/skills/write-spec/references/spec-shapes.md +0 -69
  311. /package/{plugins/freeflow/assets → assets}/freeflow-plugin-icon-transparent.png +0 -0
  312. /package/{plugins/freeflow/hooks → hooks}/hooks.json +0 -0
@@ -0,0 +1 @@
1
+ export { default } from "../dist/index.js";
@@ -0,0 +1,295 @@
1
+ import { handleNativeToolSafetyNet } from "./output-router/native-safety-net.js";
2
+ import { handleObservedToolRouting } from "./output-router/observed-tool-routing.js";
3
+ import { registerRouterTools } from "./output-router/router-tools.js";
4
+ import { handleFreeflowCommand, handleOutputRouterCommand } from "./settings/settings-ui.js";
5
+ import {
6
+ CONTRIBUTOR_COMMANDS,
7
+ WORKFLOW_COMMANDS,
8
+ WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
9
+ FREEFLOW_STATUS_TOOL_NAME,
10
+ freeflowModelSkillPaths,
11
+ freeflowSkillPath,
12
+ getRuntimeContext,
13
+ OUTPUT_ROUTER_TOOL_NAMES,
14
+ readCapabilityState,
15
+ readModeState,
16
+ readOutputRouterConfig,
17
+ refreshRuntimeContext,
18
+ restoreModeOverride,
19
+ runtimeContext,
20
+ workflowBootstrapMessage,
21
+ setModeStatus,
22
+ skillPrompt,
23
+ notifyRouterConfigWarnings,
24
+ } from "./runtime/runtime-context.js";
25
+
26
+ function isOutputRouterToolName(name: string): boolean {
27
+ return OUTPUT_ROUTER_TOOL_NAMES.includes(name);
28
+ }
29
+
30
+ async function applyCapabilityToolVisibility(pi: any, ctx: any, capabilityState = undefined): Promise<void> {
31
+ if (typeof pi?.setActiveTools !== "function" || typeof pi?.getAllTools !== "function") {
32
+ return;
33
+ }
34
+
35
+ const state = capabilityState ?? (await readCapabilityState(ctx.cwd));
36
+ const allToolNames = pi
37
+ .getAllTools()
38
+ .map((tool: any) => tool?.name)
39
+ .filter(Boolean);
40
+ const allToolNameSet = new Set(allToolNames);
41
+ const currentActive = typeof pi.getActiveTools === "function" ? pi.getActiveTools() : undefined;
42
+ const active = new Set(
43
+ (Array.isArray(currentActive) ? currentActive : allToolNames).filter((name: string) => allToolNameSet.has(name)),
44
+ );
45
+
46
+ if (allToolNameSet.has(FREEFLOW_STATUS_TOOL_NAME)) {
47
+ if (state.configured && state.enabled) active.add(FREEFLOW_STATUS_TOOL_NAME);
48
+ else active.delete(FREEFLOW_STATUS_TOOL_NAME);
49
+ }
50
+
51
+ for (const toolName of OUTPUT_ROUTER_TOOL_NAMES) {
52
+ if (!allToolNameSet.has(toolName)) continue;
53
+ if (state.outputRouter.enabled) active.add(toolName);
54
+ else active.delete(toolName);
55
+ }
56
+
57
+ pi.setActiveTools([...active]);
58
+ }
59
+
60
+ async function applyLiveCapabilityState(pi: any, ctx: any): Promise<void> {
61
+ const [modeState, capabilityState] = await Promise.all([readModeState(ctx.cwd), readCapabilityState(ctx.cwd)]);
62
+ await refreshRuntimeContext(capabilityState);
63
+ setModeStatus(ctx, modeState, capabilityState);
64
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState);
65
+ }
66
+
67
+ function disabledToolCall(toolName: string, capability: string) {
68
+ const command = capability === "freeflow" ? "/freeflow settings" : `/${capability} settings`;
69
+ return {
70
+ block: true,
71
+ reason: `${toolName} is disabled by Freeflow config. Configure ${capability} with ${command}.`,
72
+ };
73
+ }
74
+
75
+ function capabilityCompletions(prefix: string | undefined) {
76
+ const query = prefix ?? "";
77
+ return [
78
+ { value: "settings", label: "settings", description: "Open repository Output Router settings" },
79
+ { value: "status", label: "status", description: "Show effective Output Router state" },
80
+ { value: "enable", label: "enable", description: "Enable Output Router for this repository" },
81
+ { value: "disable", label: "disable", description: "Disable Output Router for this repository" },
82
+ ].filter((item) => item.value.startsWith(query));
83
+ }
84
+
85
+ function freeflowCompletions(prefix: string | undefined) {
86
+ const query = prefix ?? "";
87
+ if (query.startsWith("settings ")) {
88
+ const settingsQuery = query.slice("settings ".length);
89
+ return [
90
+ { value: "session", label: "session", description: "Override Freeflow for this Pi session" },
91
+ { value: "local", label: "local", description: "Edit personal overrides for this repository" },
92
+ { value: "repo", label: "repo", description: "Edit shared repository settings" },
93
+ ]
94
+ .filter((item) => item.value.startsWith(settingsQuery))
95
+ .map((item) => ({ ...item, value: `settings ${item.value}` }));
96
+ }
97
+ if (query.startsWith("mode ")) {
98
+ const modeQuery = query.slice("mode ".length);
99
+ return [
100
+ { value: "conversation", label: "conversation", description: "Read-only discussion and inspection" },
101
+ { value: "workflow", label: "workflow", description: "Adaptive workflow for consequential work" },
102
+ { value: "strict-workflow", label: "strict-workflow", description: "Stronger pressure at high-risk boundaries" },
103
+ {
104
+ value: "reset",
105
+ label: "reset",
106
+ description: "Clear the session override and use the configured default",
107
+ },
108
+ ]
109
+ .filter((item) => item.value.startsWith(modeQuery))
110
+ .map((item) => ({ ...item, value: `mode ${item.value}` }));
111
+ }
112
+ return [
113
+ { value: "settings", label: "settings", description: "Open personal override settings" },
114
+ { value: "status", label: "status", description: "Show effective Freeflow state" },
115
+ { value: "mode", label: "mode", description: "Select a temporary session mode" },
116
+ { value: "enable", label: "enable", description: "Enable Freeflow for this repository" },
117
+ { value: "disable", label: "disable", description: "Disable Freeflow for this repository" },
118
+ ].filter((item) => item.value.startsWith(query));
119
+ }
120
+
121
+ function bypassCompletions(prefix: string | undefined) {
122
+ const query = prefix ?? "";
123
+ return [
124
+ { value: "next", label: "next", description: "Skip one optional step" },
125
+ { value: "task", label: "task", description: "Reduce optional pressure for the current task" },
126
+ ].filter((item) => item.value.startsWith(query));
127
+ }
128
+
129
+ async function sendSkillCommand(pi: any, ctx: any, skill: string, args: string | undefined) {
130
+ const state = await readCapabilityState(ctx.cwd);
131
+ if (skill === "setup-freeflow" && !state.configured) {
132
+ await pi.sendUserMessage(skillPrompt(skill, args));
133
+ return;
134
+ }
135
+ if (!state.configured) {
136
+ ctx.ui.notify("Freeflow is installed but this repo is not set up. Run /setup-freeflow first.", "warning");
137
+ return;
138
+ }
139
+ if (!state.enabled) {
140
+ ctx.ui.notify(
141
+ "Freeflow is disabled for this repo. Use /freeflow enable or /freeflow settings to re-enable it.",
142
+ "warning",
143
+ );
144
+ return;
145
+ }
146
+ if (!state.skills.effective) {
147
+ ctx.ui.notify("Freeflow skills are disabled. Use /freeflow settings to enable skills.", "warning");
148
+ return;
149
+ }
150
+ await pi.sendUserMessage(skillPrompt(skill, args));
151
+ }
152
+
153
+ export default function freeflow(pi) {
154
+ registerRouterTools(pi);
155
+
156
+ pi.on("resources_discover", async (event, ctx) => {
157
+ const cwd = ctx?.cwd ?? event?.cwd ?? process.cwd();
158
+ const state = await readCapabilityState(cwd);
159
+ if (!state.configured) {
160
+ return { skillPaths: [freeflowSkillPath("setup-freeflow")] };
161
+ }
162
+ if (!state.enabled || !state.skills.effective) {
163
+ return { skillPaths: [] };
164
+ }
165
+ return { skillPaths: freeflowModelSkillPaths() };
166
+ });
167
+
168
+ pi.on("session_start", async (_event, ctx) => {
169
+ restoreModeOverride(ctx);
170
+ const [modeState, routerConfigResult, capabilityState] = await Promise.all([
171
+ readModeState(ctx.cwd),
172
+ readOutputRouterConfig(ctx.cwd),
173
+ readCapabilityState(ctx.cwd),
174
+ ]);
175
+ await refreshRuntimeContext(capabilityState);
176
+ setModeStatus(ctx, modeState, capabilityState);
177
+ notifyRouterConfigWarnings(ctx, routerConfigResult);
178
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState);
179
+ });
180
+
181
+ pi.on("session_tree", async (_event, ctx) => {
182
+ restoreModeOverride(ctx);
183
+ await applyLiveCapabilityState(pi, ctx);
184
+ });
185
+
186
+ pi.on("session_compact", async (_event, ctx) => {
187
+ const [modeState, routerConfigResult, capabilityState] = await Promise.all([
188
+ readModeState(ctx.cwd),
189
+ readOutputRouterConfig(ctx.cwd),
190
+ readCapabilityState(ctx.cwd),
191
+ ]);
192
+ await refreshRuntimeContext(capabilityState);
193
+ setModeStatus(ctx, modeState, capabilityState);
194
+ notifyRouterConfigWarnings(ctx, routerConfigResult);
195
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState);
196
+ });
197
+
198
+ pi.on("before_agent_start", async (event, ctx) => {
199
+ const [modeState, routerConfigResult, capabilityState] = await Promise.all([
200
+ readModeState(ctx.cwd),
201
+ readOutputRouterConfig(ctx.cwd),
202
+ readCapabilityState(ctx.cwd),
203
+ ]);
204
+ const freeflowContext = await getRuntimeContext(capabilityState);
205
+ setModeStatus(ctx, modeState, capabilityState);
206
+ notifyRouterConfigWarnings(ctx, routerConfigResult);
207
+ await applyCapabilityToolVisibility(pi, ctx, capabilityState);
208
+ const freeflowRuntimeContext = runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState);
209
+ const workflowMessage = workflowBootstrapMessage(freeflowContext, capabilityState, ctx.sessionManager);
210
+ const systemPrompt = freeflowRuntimeContext
211
+ ? `${event.systemPrompt}\n\n${freeflowRuntimeContext}`
212
+ : event.systemPrompt;
213
+ return { message: workflowMessage, systemPrompt };
214
+ });
215
+
216
+ pi.on("context", async (event, ctx) => {
217
+ const capabilityState = await readCapabilityState(ctx.cwd);
218
+ if (capabilityState.skills.effective) {
219
+ return undefined;
220
+ }
221
+
222
+ const messages = event.messages.filter(
223
+ (message) => !(message?.role === "custom" && message?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE),
224
+ );
225
+ return messages.length === event.messages.length ? undefined : { messages };
226
+ });
227
+
228
+ pi.on("tool_call", async (event, ctx) => {
229
+ const capabilityState = await readCapabilityState(ctx.cwd);
230
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
231
+ if ((!capabilityState.configured || !capabilityState.enabled) && toolName === FREEFLOW_STATUS_TOOL_NAME) {
232
+ return disabledToolCall(toolName, "freeflow");
233
+ }
234
+ if (!capabilityState.outputRouter.enabled && isOutputRouterToolName(toolName)) {
235
+ return disabledToolCall(toolName, "output-router");
236
+ }
237
+ return undefined;
238
+ });
239
+
240
+ pi.on("tool_result", async (event, ctx) => {
241
+ const capabilityState = await readCapabilityState(ctx.cwd);
242
+ if (!capabilityState.outputRouter.enabled) {
243
+ return undefined;
244
+ }
245
+ const observed = await handleObservedToolRouting(event, ctx);
246
+ if (observed) {
247
+ return observed;
248
+ }
249
+ return handleNativeToolSafetyNet(event, ctx);
250
+ });
251
+
252
+ for (const { command, skill } of WORKFLOW_COMMANDS) {
253
+ pi.registerCommand(command, {
254
+ description: command === skill ? `Run Freeflow ${skill}` : `Run Freeflow ${skill} via ${command}`,
255
+ ...(command === "bypass" ? { getArgumentCompletions: bypassCompletions } : {}),
256
+ handler: async (args, ctx) => {
257
+ await sendSkillCommand(pi, ctx, skill, args);
258
+ },
259
+ });
260
+ }
261
+
262
+ for (const skill of CONTRIBUTOR_COMMANDS) {
263
+ pi.registerCommand(skill, {
264
+ description: `Run Freeflow ${skill}`,
265
+ handler: async (args, ctx) => {
266
+ await sendSkillCommand(pi, ctx, skill, args);
267
+ },
268
+ });
269
+ }
270
+
271
+ pi.registerCommand("freeflow", {
272
+ description: "Open unified Freeflow settings or print compact status",
273
+ getArgumentCompletions: freeflowCompletions,
274
+ handler: async (args, ctx) => {
275
+ await handleFreeflowCommand(
276
+ args,
277
+ ctx,
278
+ async () => {
279
+ await applyLiveCapabilityState(pi, ctx);
280
+ },
281
+ pi,
282
+ );
283
+ },
284
+ });
285
+
286
+ pi.registerCommand("output-router", {
287
+ description: "Open Freeflow Output Router settings or print compact status",
288
+ getArgumentCompletions: capabilityCompletions,
289
+ handler: async (args, ctx) => {
290
+ await handleOutputRouterCommand(args, ctx, async () => {
291
+ await applyLiveCapabilityState(pi, ctx);
292
+ });
293
+ },
294
+ });
295
+ }
@@ -0,0 +1,32 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+
5
+ function getMcpConfigPaths(cwd) {
6
+ return [
7
+ join(homedir(), ".config", "mcp", "mcp.json"),
8
+ join(homedir(), ".pi", "agent", "mcp.json"),
9
+ resolve(cwd, ".mcp.json"),
10
+ resolve(cwd, ".pi", "mcp.json"),
11
+ ];
12
+ }
13
+
14
+ export async function isMcpServerConfigured(serverName, cwd) {
15
+ return Boolean(await loadMcpServerConfig(serverName, cwd));
16
+ }
17
+
18
+ export async function loadMcpServerConfig(serverName, cwd) {
19
+ let found = null;
20
+ for (const configPath of getMcpConfigPaths(cwd)) {
21
+ try {
22
+ const raw = JSON.parse(await readFile(configPath, "utf8"));
23
+ const servers = raw?.mcpServers ?? raw?.["mcp-servers"] ?? {};
24
+ if (servers && typeof servers === "object" && !Array.isArray(servers) && servers[serverName]) {
25
+ found = servers[serverName];
26
+ }
27
+ } catch {
28
+ // Missing or invalid MCP configs are ignored here; pi-mcp-adapter owns user-facing setup diagnostics.
29
+ }
30
+ }
31
+ return found;
32
+ }
@@ -0,0 +1,256 @@
1
+ const BUILT_IN_PI_PRODUCERS = {
2
+ web_search: {
3
+ configKey: "web",
4
+ producer: { kind: "web", tool: "web_search" },
5
+ risk: { classification: "read", source: "manifest", reason: "Pi web_search is a read-only evidence producer." },
6
+ },
7
+ fetch_content: {
8
+ configKey: "fetch",
9
+ producer: { kind: "fetch", tool: "fetch_content" },
10
+ risk: { classification: "read", source: "manifest", reason: "Pi fetch_content is a read-only evidence producer." },
11
+ },
12
+ code_search: {
13
+ configKey: "codeSearch",
14
+ producer: { kind: "code_search", tool: "code_search" },
15
+ risk: { classification: "read", source: "manifest", reason: "Pi code_search is a read-only evidence producer." },
16
+ },
17
+ } as const;
18
+
19
+ const READ_VERBS = [
20
+ "get",
21
+ "list",
22
+ "search",
23
+ "fetch",
24
+ "read",
25
+ "query",
26
+ "find",
27
+ "describe",
28
+ "diagnostic",
29
+ "diagnostics",
30
+ "overview",
31
+ "lookup",
32
+ "show",
33
+ ];
34
+
35
+ const WRITE_VERBS = [
36
+ "create",
37
+ "update",
38
+ "delete",
39
+ "remove",
40
+ "patch",
41
+ "post",
42
+ "put",
43
+ "deploy",
44
+ "restart",
45
+ "rename",
46
+ "mutate",
47
+ "set",
48
+ "write",
49
+ "send",
50
+ "transition",
51
+ "close",
52
+ "merge",
53
+ "rerun",
54
+ "cancel",
55
+ ];
56
+
57
+ export function resolvePiObservedRoutingDecision(event: any, observedRoutingConfig: any) {
58
+ const host = { name: "pi", toolName: typeof event?.toolName === "string" ? event.toolName : "unknown" };
59
+
60
+ if (!observedRoutingConfig || observedRoutingConfig.enabled !== true) {
61
+ return { route: false, reason: "observedRouting.enabled is not true." };
62
+ }
63
+
64
+ const mcpProducer = identifyPiMcpProducer(event);
65
+ if (mcpProducer) {
66
+ const serverConfig = observedRoutingConfig.mcp?.servers?.[mcpProducer.server];
67
+ if (!serverConfig?.enabled) {
68
+ return { route: false, reason: `MCP server ${mcpProducer.server} is not enabled for observed routing.` };
69
+ }
70
+ return {
71
+ route: true,
72
+ host,
73
+ producer: mcpProducer,
74
+ persistence: serverConfig.persistence,
75
+ risk: classifyObservedProducerRisk(mcpProducer, event),
76
+ };
77
+ }
78
+
79
+ const builtIn = identifyBuiltInPiProducer(event);
80
+ if (builtIn) {
81
+ const producerConfig = observedRoutingConfig[builtIn.configKey];
82
+ if (!producerConfig?.enabled) {
83
+ return { route: false, reason: `Pi ${host.toolName} observed routing is not enabled.` };
84
+ }
85
+ return {
86
+ route: true,
87
+ host,
88
+ producer: { ...builtIn.producer },
89
+ persistence: producerConfig.persistence,
90
+ risk: { ...builtIn.risk },
91
+ };
92
+ }
93
+
94
+ return { route: false, reason: `Pi tool ${host.toolName} is not an observed-routing producer.` };
95
+ }
96
+
97
+ export function identifyPiMcpProducer(event: any) {
98
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
99
+ const input = isRecord(event?.input) ? event.input : {};
100
+ const details = isRecord(event?.details) ? event.details : {};
101
+ const detailMcp = isRecord(details.mcp) ? details.mcp : {};
102
+ const inputProducer = isRecord(input.producer) ? input.producer : {};
103
+ const detailProducer = isRecord(details.producer) ? details.producer : {};
104
+ const split = splitMcpToolName(toolName);
105
+
106
+ const server = firstString(
107
+ input.server,
108
+ input.mcpServer,
109
+ inputProducer.server,
110
+ details.server,
111
+ detailMcp.server,
112
+ detailProducer.server,
113
+ split?.server,
114
+ );
115
+ const tool = firstString(
116
+ input.tool,
117
+ input.name,
118
+ inputProducer.tool,
119
+ details.tool,
120
+ detailMcp.tool,
121
+ detailProducer.tool,
122
+ split?.tool,
123
+ );
124
+
125
+ if (!server || !tool) {
126
+ return undefined;
127
+ }
128
+
129
+ if (
130
+ toolName !== "mcp" &&
131
+ !toolName.startsWith("mcp__") &&
132
+ !detailMcp.server &&
133
+ detailProducer.kind !== "mcp" &&
134
+ inputProducer.kind !== "mcp"
135
+ ) {
136
+ return undefined;
137
+ }
138
+
139
+ return { kind: "mcp", server, tool };
140
+ }
141
+
142
+ export function identifyBuiltInPiProducer(event: any) {
143
+ const toolName = typeof event?.toolName === "string" ? event.toolName : "";
144
+ return BUILT_IN_PI_PRODUCERS[toolName as keyof typeof BUILT_IN_PI_PRODUCERS];
145
+ }
146
+
147
+ export function classifyObservedProducerRisk(producer: any, event?: any) {
148
+ const configured = configuredRisk(event);
149
+ if (configured) {
150
+ return configured;
151
+ }
152
+
153
+ const annotation = mcpAnnotationRisk(event);
154
+ if (annotation) {
155
+ return annotation;
156
+ }
157
+
158
+ if (producer?.kind === "web" || producer?.kind === "fetch" || producer?.kind === "code_search") {
159
+ return {
160
+ classification: "read",
161
+ source: "manifest",
162
+ reason: `${producer.kind} is treated as a read-only Pi evidence producer.`,
163
+ };
164
+ }
165
+
166
+ const tool = typeof producer?.tool === "string" ? producer.tool : "";
167
+ if (matchesVerb(tool, WRITE_VERBS)) {
168
+ return {
169
+ classification: "write",
170
+ source: "heuristic",
171
+ reason: `MCP tool name ${tool} matched a write-like verb heuristic.`,
172
+ };
173
+ }
174
+ if (matchesVerb(tool, READ_VERBS)) {
175
+ return {
176
+ classification: "read",
177
+ source: "heuristic",
178
+ reason: `MCP tool name ${tool} matched a read-like verb heuristic.`,
179
+ };
180
+ }
181
+
182
+ return {
183
+ classification: "unknown",
184
+ source: "unknown",
185
+ reason: "No configured risk, MCP annotation, manifest entry, or deterministic name heuristic matched.",
186
+ };
187
+ }
188
+
189
+ function configuredRisk(event: any) {
190
+ const candidate = event?.details?.freeflow?.risk ?? event?.details?.observedRouting?.risk;
191
+ if (!isRecord(candidate)) {
192
+ return undefined;
193
+ }
194
+ if (!["read", "write", "unknown"].includes(String(candidate.classification))) {
195
+ return undefined;
196
+ }
197
+ return {
198
+ classification: candidate.classification,
199
+ source: "configured",
200
+ reason: typeof candidate.reason === "string" ? candidate.reason : "Configured observed producer risk override.",
201
+ };
202
+ }
203
+
204
+ function mcpAnnotationRisk(event: any) {
205
+ const annotations = event?.details?.mcp?.annotations ?? event?.details?.annotations;
206
+ if (!isRecord(annotations)) {
207
+ return undefined;
208
+ }
209
+ if (annotations.destructiveHint === true || annotations.write === true || annotations.mutating === true) {
210
+ return {
211
+ classification: "write",
212
+ source: "mcp_annotation",
213
+ reason: "MCP annotations indicate a mutating/destructive operation.",
214
+ };
215
+ }
216
+ if (annotations.readOnlyHint === true || annotations.readOnly === true) {
217
+ return {
218
+ classification: "read",
219
+ source: "mcp_annotation",
220
+ reason: "MCP annotations indicate a read-only operation.",
221
+ };
222
+ }
223
+ return undefined;
224
+ }
225
+
226
+ function splitMcpToolName(toolName: string): { server: string; tool: string } | undefined {
227
+ if (!toolName.startsWith("mcp__")) {
228
+ return undefined;
229
+ }
230
+ const parts = toolName.split("__");
231
+ if (parts.length < 3) {
232
+ return undefined;
233
+ }
234
+ return { server: parts[1], tool: parts.slice(2).join("__") };
235
+ }
236
+
237
+ function matchesVerb(toolName: string, verbs: readonly string[]): boolean {
238
+ const normalized = toolName.toLowerCase();
239
+ return verbs.some((verb) => {
240
+ const escaped = verb.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
241
+ return new RegExp(`(^|[_-])${escaped}([_-]|$)`).test(normalized);
242
+ });
243
+ }
244
+
245
+ function firstString(...values: unknown[]): string | undefined {
246
+ for (const value of values) {
247
+ if (typeof value === "string" && value.trim().length > 0) {
248
+ return value.trim();
249
+ }
250
+ }
251
+ return undefined;
252
+ }
253
+
254
+ function isRecord(value: unknown): value is Record<string, any> {
255
+ return typeof value === "object" && value !== null && !Array.isArray(value);
256
+ }