@hassangameryt/freeflow 0.7.3 → 0.8.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 (276) 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/.cursor-plugin/plugin.json +1 -1
  5. package/NOTICE +14 -0
  6. package/README.md +26 -31
  7. package/capabilities/cognitive-routing/SKILL.md +106 -161
  8. package/capabilities/cognitive-routing/references/both-mode.md +36 -0
  9. package/capabilities/cognitive-routing/references/executor-mode.md +48 -0
  10. package/capabilities/cognitive-routing/references/helper-mode.md +47 -0
  11. package/capabilities/compaction/SKILL.md +49 -0
  12. package/capabilities/compaction/references/summary-format.md +239 -0
  13. package/command-surface.json +4 -0
  14. package/gemini-extension.json +1 -1
  15. package/hooks/shared/runtime-context.mjs +28 -30
  16. package/licenses/Apache-2.0.txt +55 -0
  17. package/package.json +22 -9
  18. package/pi-extension/README.md +41 -0
  19. package/pi-extension/dist/cognitive-routing/assembler.js +393 -0
  20. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/config.js +5 -2
  21. package/pi-extension/dist/cognitive-routing/economics.js +45 -0
  22. package/pi-extension/dist/cognitive-routing/event-schema.js +388 -0
  23. package/pi-extension/dist/{session-sources/events.js → cognitive-routing/event-store.js} +103 -40
  24. package/pi-extension/dist/cognitive-routing/gate.js +241 -0
  25. package/pi-extension/dist/cognitive-routing/handlers.js +899 -0
  26. package/pi-extension/dist/cognitive-routing/handoffs.js +350 -0
  27. package/pi-extension/dist/cognitive-routing/model-control.js +467 -0
  28. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/projection.js +229 -56
  29. package/pi-extension/dist/cognitive-routing/provenance.js +81 -0
  30. package/pi-extension/dist/cognitive-routing/runtime.js +396 -0
  31. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/schemas.js +43 -7
  32. package/pi-extension/dist/cognitive-routing/session.js +221 -0
  33. package/pi-extension/dist/{session-sources → cognitive-routing}/sources.js +99 -85
  34. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/state.js +37 -378
  35. package/pi-extension/dist/cognitive-routing/status.js +80 -0
  36. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/tools.js +12 -12
  37. package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/types.js +5 -11
  38. package/pi-extension/dist/compaction/carry.js +191 -0
  39. package/pi-extension/dist/compaction/config.js +22 -0
  40. package/pi-extension/dist/compaction/controller.js +471 -0
  41. package/pi-extension/dist/compaction/harness.js +77 -0
  42. package/pi-extension/dist/compaction/results.js +158 -0
  43. package/pi-extension/dist/compaction/thresholds.js +35 -0
  44. package/pi-extension/dist/compaction/tool.js +57 -0
  45. package/pi-extension/dist/host/branch.js +13 -0
  46. package/pi-extension/dist/host/canonical.js +12 -0
  47. package/pi-extension/dist/host/catalog.js +77 -0
  48. package/pi-extension/dist/host/config.js +374 -0
  49. package/pi-extension/dist/host/projection-tags.js +60 -0
  50. package/pi-extension/dist/host/prompts.js +82 -0
  51. package/pi-extension/dist/{session-sources → host}/read-only-session.js +112 -1
  52. package/pi-extension/dist/{runtime → host}/request-history.js +121 -39
  53. package/pi-extension/dist/host/runtime-state.js +189 -0
  54. package/pi-extension/dist/{settings/settings-ui.js → host/settings/freeflow-command.js} +620 -410
  55. package/pi-extension/dist/{settings/settings-tui.js → host/settings/settings-view.js} +186 -73
  56. package/pi-extension/dist/host/staging.js +28 -0
  57. package/pi-extension/dist/host/status.js +101 -0
  58. package/pi-extension/dist/index.js +423 -173
  59. package/pi-extension/dist/provider-support/cache/anchor.js +21 -0
  60. package/pi-extension/dist/provider-support/cache/anthropic.js +102 -0
  61. package/pi-extension/dist/provider-support/cache/health.js +73 -0
  62. package/pi-extension/dist/provider-support/cache/index.js +58 -0
  63. package/pi-extension/dist/provider-support/cache/keepalive.js +210 -0
  64. package/pi-extension/dist/provider-support/cache/monitor.js +17 -0
  65. package/pi-extension/dist/provider-support/cache/openai-responses.js +48 -0
  66. package/pi-extension/dist/provider-support/effort.js +13 -0
  67. package/pi-extension/dist/provider-support/index.js +44 -3
  68. package/pi-extension/dist/provider-support/{astra → openai}/adapter.js +46 -29
  69. package/pi-extension/dist/provider-support/{astra → openai}/history.js +10 -8
  70. package/pi-extension/dist/provider-support/{astra → openai}/index.js +8 -4
  71. package/pi-extension/dist/provider-support/{astra → openai}/session-state.js +29 -38
  72. package/pi-extension/dist/provider-support/routes.js +17 -0
  73. package/pi-extension/dist/tool-execution/apply-patch/grammar.js +23 -0
  74. package/pi-extension/dist/tool-execution/apply-patch/match.js +38 -0
  75. package/pi-extension/dist/tool-execution/apply-patch/parser.js +177 -0
  76. package/pi-extension/dist/tool-execution/apply-patch/plan.js +201 -0
  77. package/pi-extension/dist/tool-execution/apply-patch/tool.js +84 -0
  78. package/pi-extension/dist/tool-execution/background.js +238 -0
  79. package/pi-extension/dist/tool-execution/bash-guard.js +23 -0
  80. package/pi-extension/dist/tool-execution/config.js +22 -0
  81. package/pi-extension/dist/tool-execution/edit-messages.js +120 -0
  82. package/pi-extension/dist/tool-execution/file-state.js +138 -0
  83. package/pi-extension/dist/tool-execution/file-tracking.js +143 -0
  84. package/pi-extension/dist/tool-execution/prompt.js +54 -0
  85. package/pi-extension/dist/tool-execution/tools.js +16 -0
  86. package/pi-extension/freeflow/README.md +9 -0
  87. package/plugin.json +1 -1
  88. package/runtime/prompts/cognitive-routing.md +4 -4
  89. package/runtime/prompts/core.md +22 -75
  90. package/runtime/prompts/interaction-contract.md +15 -8
  91. package/runtime/prompts/tool-execution.md +38 -0
  92. package/runtime/prompts/working-method.md +108 -0
  93. package/skills/action-selection/SKILL.md +39 -47
  94. package/skills/action-selection/references/trajectory-stalls.md +2 -0
  95. package/skills/bypass/SKILL.md +2 -2
  96. package/skills/commit-work/SKILL.md +31 -83
  97. package/skills/commit-work/references/git-state-edges.md +1 -1
  98. package/skills/commit-work/references/simple-push.md +2 -0
  99. package/skills/commit-work/references/staging-decisions.md +1 -1
  100. package/skills/decision-gate/SKILL.md +31 -50
  101. package/skills/design-for-depth/SKILL.md +44 -53
  102. package/skills/design-for-depth/references/design-pressure-signals.md +46 -144
  103. package/skills/design-for-depth/references/implementation-decisions.md +1 -1
  104. package/skills/design-for-depth/references/interface-design-loop.md +5 -36
  105. package/skills/design-for-depth/references/module-and-dependency-design.md +2 -32
  106. package/skills/design-for-depth/references/state-and-failure-boundaries.md +2 -13
  107. package/skills/diagnose-failure/SKILL.md +39 -24
  108. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +2 -0
  109. package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +2 -2
  110. package/skills/discuss/SKILL.md +35 -11
  111. package/skills/discuss/references/discussion-continuity.md +7 -27
  112. package/skills/evaluate-skill/SKILL.md +49 -80
  113. package/skills/evaluate-skill/references/evaluation-definition-schema.md +35 -5
  114. package/skills/evaluate-skill/references/evaluation-design.md +14 -14
  115. package/skills/evaluate-skill/references/execution-and-evidence.md +26 -5
  116. package/skills/evaluate-skill/references/review-and-revision.md +3 -1
  117. package/skills/evaluate-skill/scripts/lib/definitions.mjs +49 -8
  118. package/skills/evaluate-skill/scripts/lib/pi.mjs +14 -7
  119. package/skills/evaluate-skill/scripts/lib/review.mjs +196 -0
  120. package/skills/evaluate-skill/scripts/lib/runner.mjs +45 -8
  121. package/skills/evaluate-skill/scripts/lib/sandbox.mjs +2 -0
  122. package/skills/evaluate-skill/scripts/lib/trials.mjs +103 -0
  123. package/skills/evaluate-skill/scripts/lib/view.mjs +67 -1
  124. package/skills/evaluate-skill/scripts/pi-command-tool.mjs +144 -0
  125. package/skills/evaluate-skill/scripts/pi-guard.mjs +30 -13
  126. package/skills/evaluate-skill/scripts/skill-eval.mjs +114 -34
  127. package/skills/execute-work/SKILL.md +41 -9
  128. package/skills/execute-work/references/code-practices.md +2 -0
  129. package/skills/execute-work/references/execute-work-edges.md +11 -1
  130. package/skills/handoff/SKILL.md +1 -1
  131. package/skills/handoff/references/handoff-templates.md +1 -1
  132. package/skills/review-artifact/SKILL.md +42 -41
  133. package/skills/review-artifact/references/adjudicate-artifact-review.md +1 -1
  134. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +1 -1
  135. package/skills/review-work/SKILL.md +38 -32
  136. package/skills/review-work/references/adjudicate-work-review.md +1 -1
  137. package/skills/review-work/references/independent-work-reviewer-contract.md +1 -1
  138. package/skills/review-work/references/security-risk-lens.md +2 -4
  139. package/skills/setup-freeflow/SKILL.md +3 -1
  140. package/skills/setup-freeflow/references/activation-contract.md +7 -13
  141. package/skills/setup-freeflow/references/host-setup.md +3 -3
  142. package/skills/track-work/SKILL.md +113 -161
  143. package/skills/track-work/references/working-record-format.md +189 -350
  144. package/skills/track-work/scripts/lib/document.mjs +62 -6
  145. package/skills/track-work/scripts/lib/format.mjs +16 -1
  146. package/skills/track-work/scripts/lib/store.mjs +9 -8
  147. package/skills/track-work/scripts/lib/transitions.mjs +79 -4
  148. package/skills/track-work/scripts/working-record.mjs +34 -12
  149. package/skills/verify-work/SKILL.md +29 -20
  150. package/skills/verify-work/references/browser-runtime-evidence.md +1 -5
  151. package/skills/verify-work/references/integration-evidence.md +2 -0
  152. package/skills/verify-work/references/performance-evidence.md +3 -1
  153. package/skills/verify-work/references/test-design.md +3 -1
  154. package/skills/workflow/SKILL.md +65 -21
  155. package/skills/workflow/references/domain-skill-composition.md +5 -3
  156. package/skills/write-docs/SKILL.md +83 -0
  157. package/skills/write-docs/references/documentation-shapes.md +119 -0
  158. package/skills/write-docs/scripts/docs-check.mjs +139 -0
  159. package/skills/write-plan/SKILL.md +40 -40
  160. package/skills/write-plan/references/plan-shapes.md +1 -1
  161. package/skills/write-skill/SKILL.md +107 -147
  162. package/skills/write-skill/references/activation-boundaries.md +2 -0
  163. package/skills/write-skill/references/agent-first-instructions.md +22 -10
  164. package/skills/write-skill/references/progressive-disclosure.md +4 -2
  165. package/skills/write-skill/references/skill-dependency-graphs.md +2 -0
  166. package/skills/write-skill/scripts/lib/similarity.mjs +56 -0
  167. package/skills/write-skill/scripts/skill-author.mjs +18 -2
  168. package/skills/write-spec/SKILL.md +34 -41
  169. package/skills/write-spec/references/artifact-standards.md +1 -1
  170. package/skills/write-spec/references/decision-records.md +2 -0
  171. package/skills/write-spec/references/spec-shapes.md +1 -1
  172. package/capabilities/context-virtualization/SKILL.md +0 -103
  173. package/capabilities/conversation-history/SKILL.md +0 -53
  174. package/hooks/tests/check-host-adapters.test.mjs +0 -82
  175. package/hooks/tests/check-runtime-context-hook.sh +0 -212
  176. package/pi-extension/dist/cognitive-routing-v2/runtime.js +0 -2181
  177. package/pi-extension/dist/context-virtualization/commands.js +0 -89
  178. package/pi-extension/dist/context-virtualization/projector.js +0 -42
  179. package/pi-extension/dist/context-virtualization/runtime.js +0 -378
  180. package/pi-extension/dist/context-virtualization/state.js +0 -57
  181. package/pi-extension/dist/context-virtualization/types.js +0 -10
  182. package/pi-extension/dist/conversation-history/passages.js +0 -66
  183. package/pi-extension/dist/conversation-history/ranking.js +0 -105
  184. package/pi-extension/dist/conversation-history/runtime.js +0 -226
  185. package/pi-extension/dist/conversation-history/search.js +0 -56
  186. package/pi-extension/dist/conversation-history/types.js +0 -1
  187. package/pi-extension/dist/freeflow-context/resolver.js +0 -120
  188. package/pi-extension/dist/freeflow-context/runtime.js +0 -80
  189. package/pi-extension/dist/freeflow-context/source-projector.js +0 -95
  190. package/pi-extension/dist/freeflow-context/tool.js +0 -314
  191. package/pi-extension/dist/freeflow-context/types.js +0 -12
  192. package/pi-extension/dist/freeflow-context/visibility.js +0 -28
  193. package/pi-extension/dist/integrations/mcp-config.js +0 -29
  194. package/pi-extension/dist/runtime/runtime-context.js +0 -754
  195. package/pi-extension/dist/runtime/runtime-identity.js +0 -5
  196. package/pi-extension/dist/session-sources/provenance.js +0 -32
  197. package/pi-extension/dist/ui/text-component.js +0 -57
  198. package/pi-extension/src/cognitive-routing-v2/budget.ts +0 -42
  199. package/pi-extension/src/cognitive-routing-v2/config.ts +0 -173
  200. package/pi-extension/src/cognitive-routing-v2/projection.ts +0 -375
  201. package/pi-extension/src/cognitive-routing-v2/render.ts +0 -277
  202. package/pi-extension/src/cognitive-routing-v2/runtime.ts +0 -2241
  203. package/pi-extension/src/cognitive-routing-v2/schemas.ts +0 -180
  204. package/pi-extension/src/cognitive-routing-v2/state.ts +0 -839
  205. package/pi-extension/src/cognitive-routing-v2/tools.ts +0 -62
  206. package/pi-extension/src/cognitive-routing-v2/types.ts +0 -254
  207. package/pi-extension/src/context-virtualization/commands.ts +0 -111
  208. package/pi-extension/src/context-virtualization/projector.ts +0 -62
  209. package/pi-extension/src/context-virtualization/runtime.ts +0 -428
  210. package/pi-extension/src/context-virtualization/state.ts +0 -79
  211. package/pi-extension/src/context-virtualization/types.ts +0 -92
  212. package/pi-extension/src/conversation-history/passages.ts +0 -81
  213. package/pi-extension/src/conversation-history/ranking.ts +0 -155
  214. package/pi-extension/src/conversation-history/runtime.ts +0 -250
  215. package/pi-extension/src/conversation-history/search.ts +0 -79
  216. package/pi-extension/src/conversation-history/types.ts +0 -31
  217. package/pi-extension/src/freeflow-context/resolver.ts +0 -139
  218. package/pi-extension/src/freeflow-context/runtime.ts +0 -100
  219. package/pi-extension/src/freeflow-context/source-projector.ts +0 -106
  220. package/pi-extension/src/freeflow-context/tool.ts +0 -366
  221. package/pi-extension/src/freeflow-context/types.ts +0 -70
  222. package/pi-extension/src/freeflow-context/visibility.ts +0 -53
  223. package/pi-extension/src/index.ts +0 -390
  224. package/pi-extension/src/integrations/mcp-config.ts +0 -32
  225. package/pi-extension/src/provider-support/astra/adapter.ts +0 -108
  226. package/pi-extension/src/provider-support/astra/history.ts +0 -145
  227. package/pi-extension/src/provider-support/astra/index.ts +0 -12
  228. package/pi-extension/src/provider-support/astra/session-state.ts +0 -113
  229. package/pi-extension/src/provider-support/index.ts +0 -5
  230. package/pi-extension/src/runtime/request-history.ts +0 -243
  231. package/pi-extension/src/runtime/runtime-context.ts +0 -860
  232. package/pi-extension/src/runtime/runtime-identity.ts +0 -8
  233. package/pi-extension/src/session-sources/events.ts +0 -230
  234. package/pi-extension/src/session-sources/provenance.ts +0 -39
  235. package/pi-extension/src/session-sources/read-only-session.ts +0 -170
  236. package/pi-extension/src/session-sources/sources.ts +0 -334
  237. package/pi-extension/src/settings/settings-tui.ts +0 -501
  238. package/pi-extension/src/settings/settings-ui.ts +0 -1652
  239. package/pi-extension/src/ui/text-component.ts +0 -66
  240. package/pi-extension/tests/cache-reuse/history.test.js +0 -117
  241. package/pi-extension/tests/cache-reuse/native.test.js +0 -91
  242. package/pi-extension/tests/cache-reuse/settings.test.js +0 -211
  243. package/pi-extension/tests/cognitive-routing-v2/communication.test.js +0 -577
  244. package/pi-extension/tests/cognitive-routing-v2/compaction-input.test.js +0 -183
  245. package/pi-extension/tests/cognitive-routing-v2/delegation.test.js +0 -557
  246. package/pi-extension/tests/cognitive-routing-v2/native.test.js +0 -474
  247. package/pi-extension/tests/cognitive-routing-v2/performance.test.js +0 -87
  248. package/pi-extension/tests/cognitive-routing-v2/persistence.test.js +0 -300
  249. package/pi-extension/tests/cognitive-routing-v2/projection.test.js +0 -241
  250. package/pi-extension/tests/cognitive-routing-v2/recovery.test.js +0 -1034
  251. package/pi-extension/tests/cognitive-routing-v2/render.test.js +0 -244
  252. package/pi-extension/tests/cognitive-routing-v2/runtime.test.js +0 -423
  253. package/pi-extension/tests/cognitive-routing-v2/stabilization.test.js +0 -521
  254. package/pi-extension/tests/cognitive-routing-v2/state.test.js +0 -586
  255. package/pi-extension/tests/context-virtualization/extension.test.js +0 -775
  256. package/pi-extension/tests/context-virtualization/projector.test.js +0 -110
  257. package/pi-extension/tests/context-virtualization/runtime.test.js +0 -230
  258. package/pi-extension/tests/conversation-history/runtime.test.js +0 -98
  259. package/pi-extension/tests/conversation-history/search.test.js +0 -97
  260. package/pi-extension/tests/fixtures/pi-host.js +0 -4
  261. package/pi-extension/tests/fixtures/routing-native.js +0 -191
  262. package/pi-extension/tests/integration/mode-free-core.test.js +0 -220
  263. package/pi-extension/tests/integration/pi-extension.test.js +0 -1447
  264. package/pi-extension/tests/integration/prompt-architecture.test.js +0 -447
  265. package/pi-extension/tests/integration/unaffected-regressions.test.js +0 -478
  266. package/pi-extension/tests/provider-support/astra-boundaries.test.js +0 -75
  267. package/pi-extension/tests/provider-support/astra.test.js +0 -306
  268. package/pi-extension/tests/provider-support/cli.test.js +0 -92
  269. package/pi-extension/tests/provider-support/native.test.js +0 -183
  270. package/pi-extension/tests/settings/settings-tui.test.js +0 -243
  271. package/pi-extension/tsconfig.json +0 -16
  272. package/runtime/prompts/context-virtualization.md +0 -3
  273. package/runtime/prompts/conversation-history.md +0 -3
  274. package/skills/design-for-depth/references/software-design-philosophy.md +0 -202
  275. /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/budget.js +0 -0
  276. /package/pi-extension/dist/{cognitive-routing-v2 → cognitive-routing}/render.js +0 -0
@@ -1,557 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import { writeFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import test from "node:test";
5
- import { resolveCognitiveRoutingState } from "../../dist/cognitive-routing-v2/config.js";
6
- import { RoutingRuntime } from "../../dist/cognitive-routing-v2/runtime.js";
7
- import { replay } from "../../dist/cognitive-routing-v2/state.js";
8
- import { fixture } from "../fixtures/routing-native.js";
9
-
10
- const coordinator = { provider: "openai", model: "gpt-4o", thinking: "off" };
11
- const worker = { provider: "openai", model: "gpt-4.1-mini", thinking: "off" };
12
- const alternateExecutor = { provider: "openai", model: "gpt-4.1", thinking: "off" };
13
- const bothConfig = {
14
- enabled: true,
15
- delegation: "both",
16
- projection: true,
17
- profiles: { coordinator, helper: worker, executor: worker },
18
- };
19
- const helperConfig = {
20
- enabled: true,
21
- delegation: "helper",
22
- projection: true,
23
- profiles: { coordinator, helper: worker },
24
- };
25
-
26
- function registry(available = ["coordinator", "helper", "executor"]) {
27
- const models = {
28
- coordinator: { provider: "test", id: "coordinator", reasoning: true },
29
- helper: { provider: "test", id: "helper", reasoning: true },
30
- executor: { provider: "test", id: "executor", reasoning: true },
31
- };
32
- return {
33
- find(_provider, id) {
34
- return available.includes(id) ? models[id] : undefined;
35
- },
36
- async getApiKeyAndHeaders() {
37
- return { ok: true };
38
- },
39
- clampThinkingLevel(_model, level) {
40
- return level;
41
- },
42
- };
43
- }
44
-
45
- const profile = (model) => ({ provider: "test", model, thinking: "off" });
46
-
47
- test("delegation modes validate only enabled worker presets and preserve the executor default", async () => {
48
- const legacy = await resolveCognitiveRoutingState(
49
- {
50
- cognitiveRouting: {
51
- enabled: true,
52
- profiles: {
53
- coordinator: profile("coordinator"),
54
- executor: profile("executor"),
55
- helper: profile("missing-unused-helper"),
56
- },
57
- },
58
- },
59
- {},
60
- { modelRegistry: registry() },
61
- );
62
- assert.equal(legacy.delegation, "executor");
63
- assert.equal(legacy.delegationSource, "default");
64
- assert.equal(legacy.effective, true, "an unavailable unused Helper preset does not block executor-only mode");
65
-
66
- const helperOnly = await resolveCognitiveRoutingState(
67
- {
68
- cognitiveRouting: {
69
- enabled: true,
70
- delegation: "helper",
71
- profiles: { coordinator: profile("coordinator"), helper: profile("helper") },
72
- },
73
- },
74
- {},
75
- { modelRegistry: registry() },
76
- );
77
- assert.equal(helperOnly.effective, true, "helper-only does not require Executor");
78
-
79
- const missingBoth = await resolveCognitiveRoutingState(
80
- {
81
- cognitiveRouting: {
82
- enabled: true,
83
- delegation: "both",
84
- profiles: { coordinator: profile("coordinator"), helper: profile("helper") },
85
- },
86
- },
87
- {},
88
- { modelRegistry: registry() },
89
- );
90
- assert.equal(missingBoth.effective, false);
91
- assert.equal(missingBoth.blockingReason.code, "profile_missing");
92
- assert.match(missingBoth.blockingReason.message, /executor/i);
93
-
94
- const personalMode = await resolveCognitiveRoutingState(
95
- {
96
- cognitiveRouting: {
97
- enabled: true,
98
- delegation: "executor",
99
- profiles: { coordinator: profile("coordinator"), executor: profile("executor") },
100
- },
101
- },
102
- {
103
- cognitiveRouting: {
104
- delegation: "helper",
105
- profiles: { helper: profile("helper") },
106
- },
107
- },
108
- { modelRegistry: registry() },
109
- );
110
- assert.equal(personalMode.effective, true);
111
- assert.equal(personalMode.delegation, "helper");
112
- assert.equal(personalMode.delegationSource, "personal");
113
-
114
- const malformedUnused = await resolveCognitiveRoutingState(
115
- {
116
- cognitiveRouting: {
117
- enabled: true,
118
- profiles: {
119
- coordinator: profile("coordinator"),
120
- executor: profile("executor"),
121
- helper: { provider: "test", model: "helper" },
122
- },
123
- },
124
- },
125
- {},
126
- { modelRegistry: registry() },
127
- );
128
- assert.equal(malformedUnused.configValid, false, "malformed unused presets remain invalid configuration");
129
- });
130
-
131
- test("a duplicate delegation operation cannot change its recorded worker", { timeout: 30000 }, async () => {
132
- const originalInvoke = RoutingRuntime.prototype.invoke;
133
- let checked = false;
134
- RoutingRuntime.prototype.invoke = async function (name, id, input, signal, ctx) {
135
- const result = await originalInvoke.call(this, name, id, input, signal, ctx);
136
- if (!checked && name === "freeflow_delegate" && input.worker === "helper") {
137
- checked = true;
138
- this.receipts.clear();
139
- const conflict = await originalInvoke.call(this, name, id, { ...input, worker: "executor" }, signal, ctx);
140
- assert.equal(conflict.details.code, "operation_conflict");
141
- }
142
- return result;
143
- };
144
- try {
145
- const result = await fixture(
146
- (n) =>
147
- n === 1
148
- ? [
149
- {
150
- name: "freeflow_delegate",
151
- args: { operation: "assign", worker: "helper", contract: "Keep the accepted Helper identity." },
152
- },
153
- ]
154
- : n === 2
155
- ? [
156
- {
157
- name: "freeflow_return",
158
- args: { operation: "submit", report: "Helper identity retained.", outcome: "completed" },
159
- },
160
- ]
161
- : n === 3
162
- ? [
163
- {
164
- name: "freeflow_unit",
165
- args: { operation: "close", outcome: "accepted", assessment: "Worker identity is stable." },
166
- },
167
- ]
168
- : [],
169
- true,
170
- undefined,
171
- true,
172
- { cognitiveRouting: bothConfig, maxRequests: 5 },
173
- );
174
- assert.equal(checked, true);
175
- assert.equal([...result.state.handoffs.values()].find((handoff) => handoff.kind === "delegate").to, "helper");
176
- } finally {
177
- RoutingRuntime.prototype.invoke = originalInvoke;
178
- }
179
- });
180
-
181
- test("both mode requires an explicit worker and shares Helper history with Executor", { timeout: 30000 }, async () => {
182
- let helperReadId;
183
- const result = await fixture(
184
- (n, body, manager) => {
185
- const wire = JSON.stringify(body);
186
- if (n === 1) return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Ambiguous worker." } }];
187
- if (n === 2) {
188
- assert.equal(replay(manager.getBranch()).assignments.size, 0, "ambiguous delegation appends no assignment");
189
- return [
190
- {
191
- name: "freeflow_delegate",
192
- args: { operation: "assign", worker: "helper", contract: "Read the marker for later implementation." },
193
- },
194
- ];
195
- }
196
- if (n === 3) {
197
- assert.equal(body.model, "gpt-4.1-mini");
198
- assert.equal(replay(manager.getBranch()).profile, "helper");
199
- return [{ name: "read", args: { path: "unselected.txt" } }];
200
- }
201
- if (n === 4) {
202
- const read = manager
203
- .getBranch()
204
- .filter((entry) => entry.message?.toolName === "read")
205
- .at(-1);
206
- helperReadId = read.id;
207
- assert.equal(read.message.isError, false);
208
- assert.match(wire, /UNSELECTED_PRIVATE_BODY_93/);
209
- return [
210
- {
211
- name: "freeflow_return",
212
- args: { operation: "submit", report: "Helper context gathered.", outcome: "completed" },
213
- },
214
- ];
215
- }
216
- if (n === 5) {
217
- assert.equal(body.model, "gpt-4o");
218
- assert.equal(replay(manager.getBranch()).profile, "coordinator");
219
- assert.doesNotMatch(
220
- wire,
221
- /UNSELECTED_PRIVATE_BODY_93/,
222
- "unselected Helper result stays out of Coordinator view",
223
- );
224
- return [
225
- {
226
- name: "freeflow_delegate",
227
- args: { operation: "assign", worker: "executor", contract: "Use the gathered marker and report." },
228
- },
229
- ];
230
- }
231
- if (n === 6) {
232
- assert.equal(body.model, "gpt-4.1-mini");
233
- assert.equal(replay(manager.getBranch()).profile, "executor");
234
- assert.match(wire, /UNSELECTED_PRIVATE_BODY_93/, "Executor inherits ordinary Helper history");
235
- assert.equal(
236
- manager.getBranch().filter((entry) => entry.message?.toolName === "read").length,
237
- 1,
238
- "Executor does not rerun Helper's read",
239
- );
240
- return [
241
- {
242
- name: "freeflow_project",
243
- args: { operation: "add", refs: [`ctx:${helperReadId}`] },
244
- },
245
- {
246
- name: "freeflow_return",
247
- args: { operation: "submit", report: "Executor used shared context.", outcome: "completed" },
248
- },
249
- ];
250
- }
251
- if (n === 7) {
252
- assert.equal(body.model, "gpt-4o");
253
- assert.match(wire, /UNSELECTED_PRIVATE_BODY_93/);
254
- assert.match(wire, /producer: helper/);
255
- return [
256
- {
257
- name: "freeflow_unit",
258
- args: { operation: "close", outcome: "accepted", assessment: "Shared worker context observed." },
259
- },
260
- ];
261
- }
262
- return [];
263
- },
264
- true,
265
- undefined,
266
- true,
267
- { cognitiveRouting: bothConfig, maxRequests: 9 },
268
- );
269
- assert.equal(result.requests.length, 8);
270
- assert.equal(result.state.units.values().next().value.state, "closed");
271
- const delegates = [...result.state.handoffs.values()].filter((handoff) => handoff.kind === "delegate");
272
- assert.deepEqual(
273
- delegates.map((handoff) => handoff.to),
274
- ["helper", "executor"],
275
- );
276
- });
277
-
278
- test(
279
- "helper-only rejects Executor delegation and recovers through the recorded Helper",
280
- { timeout: 30000 },
281
- async () => {
282
- let assignmentId, baseReportId;
283
- const result = await fixture(
284
- (n, body, manager) => {
285
- if (n === 1)
286
- return [
287
- {
288
- name: "freeflow_delegate",
289
- args: { operation: "assign", worker: "executor", contract: "Disabled target." },
290
- },
291
- ];
292
- if (n === 2) {
293
- assert.equal(replay(manager.getBranch()).assignments.size, 0);
294
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Return then recover." } }];
295
- }
296
- if (n === 3) {
297
- const state = replay(manager.getBranch());
298
- assignmentId = state.assignmentId;
299
- assert.equal(state.profile, "helper");
300
- return [
301
- {
302
- name: "freeflow_return",
303
- args: { operation: "submit", report: "Helper base report.", outcome: "completed" },
304
- },
305
- ];
306
- }
307
- if (n === 4) {
308
- const state = replay(manager.getBranch());
309
- baseReportId = state.assignments.get(assignmentId).returnHandoffId;
310
- return [
311
- {
312
- name: "freeflow_unit",
313
- args: { operation: "recover", request: "Read the approved recovery file.", paths: ["recovery.txt"] },
314
- },
315
- ];
316
- }
317
- if (n === 5) {
318
- assert.equal(replay(manager.getBranch()).profile, "helper");
319
- return [{ name: "read", args: { path: "recovery.txt" } }];
320
- }
321
- if (n === 6)
322
- return [
323
- {
324
- name: "freeflow_return",
325
- args: { operation: "supplement", report: "Helper recovery supplement.", outcome: "completed" },
326
- },
327
- ];
328
- if (n === 7) {
329
- const state = replay(manager.getBranch());
330
- assert.equal(state.assignmentId, assignmentId);
331
- assert.equal(state.assignments.get(assignmentId).returnHandoffId, baseReportId);
332
- assert.equal(state.handoffs.get(baseReportId).text, "Helper base report.");
333
- const completed = [...state.recoveries.values()].at(-1);
334
- assert.equal(completed.state, "completed");
335
- assert.equal(state.handoffs.get(completed.requestHandoffId).to, "helper");
336
- assert.equal(state.handoffs.get(completed.supplementHandoffId).from, "helper");
337
- return [
338
- {
339
- name: "freeflow_unit",
340
- args: { operation: "close", outcome: "accepted", assessment: "Helper recovery retained lineage." },
341
- },
342
- ];
343
- }
344
- return [];
345
- },
346
- true,
347
- undefined,
348
- true,
349
- { cognitiveRouting: helperConfig, maxRequests: 9 },
350
- );
351
- assert.equal(result.requests.length, 8);
352
- },
353
- );
354
-
355
- test("new input routes through Coordinator before the same Helper assignment resumes", { timeout: 30000 }, async () => {
356
- let assignmentId;
357
- const result = await fixture(
358
- (n, body, manager) => {
359
- if (n === 1)
360
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Keep the Helper task." } }];
361
- if (n === 2) {
362
- assignmentId = replay(manager.getBranch()).assignmentId;
363
- assert.equal(replay(manager.getBranch()).profile, "helper");
364
- return [];
365
- }
366
- if (n === 3) {
367
- const state = replay(manager.getBranch());
368
- assert.equal(body.model, "gpt-4o");
369
- assert.equal(state.profile, "coordinator");
370
- assert.equal(state.assignments.get(assignmentId).state, "outstanding");
371
- return [];
372
- }
373
- if (n === 4) {
374
- const state = replay(manager.getBranch());
375
- assert.equal(state.profile, "helper");
376
- assert.equal(state.assignmentId, assignmentId);
377
- assert.doesNotMatch(JSON.stringify(body), /New delivered user input requires Coordinator attention/);
378
- return [
379
- {
380
- name: "freeflow_return",
381
- args: { operation: "submit", report: "Helper resumed after Coordinator attention.", outcome: "completed" },
382
- },
383
- ];
384
- }
385
- return [];
386
- },
387
- true,
388
- async ({ session }) => {
389
- await session.prompt("Consider this new direction before continuing.");
390
- await session.waitForIdle();
391
- await session.prompt("/freeflow resume");
392
- await session.waitForIdle();
393
- },
394
- true,
395
- { cognitiveRouting: helperConfig, maxRequests: 6 },
396
- );
397
- assert.equal(result.requests.length, 5);
398
- assert.equal(result.state.assignments.get(assignmentId).state, "returned");
399
- });
400
-
401
- test("an accepted Helper assignment survives a later executor-only mode change", { timeout: 30000 }, async () => {
402
- let assignmentId;
403
- const result = await fixture(
404
- (n, body, manager) => {
405
- if (n === 1)
406
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Keep this Helper assignment." } }];
407
- if (n === 2) {
408
- assignmentId = replay(manager.getBranch()).assignmentId;
409
- assert.equal(replay(manager.getBranch()).profile, "helper");
410
- return [];
411
- }
412
- if (n === 3) {
413
- const state = replay(manager.getBranch());
414
- assert.equal(state.assignmentId, assignmentId);
415
- assert.equal(state.profile, "helper");
416
- assert.equal(body.model, "gpt-4.1-mini");
417
- assert.notEqual(body.model, alternateExecutor.model, "resume does not use the newly enabled Executor pair");
418
- return [
419
- {
420
- name: "freeflow_return",
421
- args: { operation: "submit", report: "Original Helper assignment resumed.", outcome: "completed" },
422
- },
423
- ];
424
- }
425
- if (n === 4)
426
- return [
427
- {
428
- name: "freeflow_unit",
429
- args: { operation: "close", outcome: "accepted", assessment: "Mode change did not retarget work." },
430
- },
431
- ];
432
- return [];
433
- },
434
- true,
435
- async ({ session, cwd }) => {
436
- await writeFile(
437
- join(cwd, ".freeflow/config.json"),
438
- JSON.stringify({
439
- cognitiveRouting: {
440
- enabled: true,
441
- delegation: "executor",
442
- projection: true,
443
- profiles: { coordinator, helper: worker, executor: alternateExecutor },
444
- },
445
- }),
446
- );
447
- await session.reload();
448
- await session.prompt("/freeflow resume");
449
- await session.waitForIdle();
450
- },
451
- true,
452
- { cognitiveRouting: helperConfig, maxRequests: 6 },
453
- );
454
- assert.equal(result.requests.length, 5);
455
- assert.equal(result.state.assignments.get(assignmentId).state, "returned");
456
- });
457
-
458
- test(
459
- "an outstanding Helper assignment fails closed when its preset becomes unavailable",
460
- { timeout: 30000 },
461
- async () => {
462
- let assignmentId, delegateHandoffId;
463
- const result = await fixture(
464
- (n, body, manager) => {
465
- if (n === 1)
466
- return [
467
- { name: "freeflow_delegate", args: { operation: "assign", contract: "Retain unavailable Helper work." } },
468
- ];
469
- if (n === 2) {
470
- const state = replay(manager.getBranch());
471
- assignmentId = state.assignmentId;
472
- delegateHandoffId = state.assignments.get(assignmentId).delegateHandoffId;
473
- assert.equal(state.profile, "helper");
474
- return [];
475
- }
476
- assert.fail(`blocked continuation unexpectedly reached the provider with ${body.model}`);
477
- },
478
- true,
479
- async ({ session, cwd, requests, notices }) => {
480
- await writeFile(
481
- join(cwd, ".freeflow/config.json"),
482
- JSON.stringify({
483
- cognitiveRouting: {
484
- enabled: true,
485
- delegation: "executor",
486
- projection: true,
487
- profiles: { coordinator, executor: alternateExecutor },
488
- },
489
- }),
490
- );
491
- await session.reload();
492
- const requestCount = requests.length;
493
- await session.prompt("/freeflow resume");
494
- await session.waitForIdle();
495
- assert.equal(requests.length, requestCount, "blocked resume makes no provider request");
496
- assert.equal(session.model.id, "gpt-4.1-mini", "no fallback setter applies the Executor pair");
497
- assert.match(JSON.stringify(notices), /profile_missing|helper/i);
498
- },
499
- true,
500
- { cognitiveRouting: helperConfig, maxRequests: 4 },
501
- );
502
- assert.equal(result.requests.length, 2);
503
- assert.equal(result.state.assignmentId, assignmentId);
504
- assert.equal(result.state.assignments.get(assignmentId).state, "outstanding");
505
- assert.equal(result.state.assignments.get(assignmentId).delegateHandoffId, delegateHandoffId);
506
- assert.equal(result.state.handoffs.get(delegateHandoffId).to, "helper");
507
- assert.equal(
508
- [...result.state.handoffs.values()].some((handoff) => handoff.kind === "return"),
509
- false,
510
- );
511
- },
512
- );
513
-
514
- test("compaction and explicit resume preserve a Helper assignment", { timeout: 30000 }, async () => {
515
- let assignmentId, basis;
516
- const result = await fixture(
517
- (n, body, manager) => {
518
- if (n === 1)
519
- return [{ name: "freeflow_delegate", args: { operation: "assign", contract: "Preserve Helper work." } }];
520
- if (n === 2) {
521
- const state = replay(manager.getBranch());
522
- assignmentId = state.assignmentId;
523
- basis = state.assignments.get(assignmentId).basisUserEntryId;
524
- return [{ name: "read", args: { path: "evidence.txt" } }];
525
- }
526
- if (n === 4) {
527
- const state = replay(manager.getBranch());
528
- assert.equal(state.profile, "helper");
529
- assert.equal(state.assignmentId, assignmentId);
530
- assert.equal(state.resumeBasis.get(assignmentId), basis);
531
- assert.doesNotMatch(JSON.stringify(body), /New delivered user input requires Coordinator attention/);
532
- return [
533
- {
534
- name: "freeflow_return",
535
- args: { operation: "submit", report: "Helper resumed after compaction.", outcome: "completed" },
536
- },
537
- ];
538
- }
539
- return [];
540
- },
541
- true,
542
- async ({ session, manager }) => {
543
- await session.compact();
544
- assert.equal(
545
- manager.buildSessionContext().messages.some((message) => message.role === "user"),
546
- false,
547
- );
548
- await session.reload();
549
- await session.prompt("/freeflow resume");
550
- await session.waitForIdle();
551
- },
552
- true,
553
- { cognitiveRouting: helperConfig, maxRequests: 6 },
554
- );
555
- assert.equal(result.requests.length, 5);
556
- assert.equal(result.state.assignments.get(assignmentId).state, "returned");
557
- });