@hassangameryt/freeflow 0.6.0 → 0.7.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 (122) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +4 -5
  4. package/README.md +39 -55
  5. package/capabilities/cognitive-routing/SKILL.md +288 -130
  6. package/command-surface.json +0 -24
  7. package/hooks/freeflow-runtime-context.mjs +42 -477
  8. package/hooks/hooks.json +1 -26
  9. package/hooks/tests/check-runtime-context-hook.sh +108 -319
  10. package/package.json +4 -2
  11. package/pi-extension/dist/cognitive-routing/commands.js +3 -3
  12. package/pi-extension/dist/cognitive-routing/config.js +16 -20
  13. package/pi-extension/dist/cognitive-routing/controller.js +478 -48
  14. package/pi-extension/dist/cognitive-routing/history.js +12 -0
  15. package/pi-extension/dist/cognitive-routing/host.js +74 -12
  16. package/pi-extension/dist/cognitive-routing/pi-routing-session.js +414 -0
  17. package/pi-extension/dist/cognitive-routing/pi-session-control.js +320 -0
  18. package/pi-extension/dist/cognitive-routing/tool.js +1 -0
  19. package/pi-extension/dist/cognitive-routing/types.js +1 -1
  20. package/pi-extension/dist/index.js +236 -219
  21. package/pi-extension/dist/runtime/runtime-context.js +126 -286
  22. package/pi-extension/dist/settings/settings-ui.js +52 -336
  23. package/pi-extension/src/cognitive-routing/commands.ts +15 -5
  24. package/pi-extension/src/cognitive-routing/config.ts +16 -20
  25. package/pi-extension/src/cognitive-routing/controller.ts +561 -51
  26. package/pi-extension/src/cognitive-routing/history.ts +12 -0
  27. package/pi-extension/src/cognitive-routing/host.ts +110 -16
  28. package/pi-extension/src/cognitive-routing/pi-routing-session.ts +538 -0
  29. package/pi-extension/src/cognitive-routing/pi-session-control.ts +444 -0
  30. package/pi-extension/src/cognitive-routing/tool.ts +1 -0
  31. package/pi-extension/src/cognitive-routing/types.ts +1 -1
  32. package/pi-extension/src/index.ts +249 -239
  33. package/pi-extension/src/runtime/runtime-context.ts +129 -305
  34. package/pi-extension/src/settings/settings-ui.ts +53 -371
  35. package/pi-extension/tests/cognitive-routing/commands.test.js +1 -1
  36. package/pi-extension/tests/cognitive-routing/controller.test.js +69 -40
  37. package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +128 -57
  38. package/pi-extension/tests/cognitive-routing/pi-normal-lifecycle.test.js +434 -0
  39. package/pi-extension/tests/cognitive-routing/pi-session-control.test.js +174 -0
  40. package/pi-extension/tests/cognitive-routing/pi-session-history.test.js +91 -0
  41. package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +47 -4
  42. package/pi-extension/tests/integration/mode-free-core.test.js +218 -0
  43. package/pi-extension/tests/integration/pi-extension.test.js +430 -2478
  44. package/pi-extension/tests/integration/prompt-architecture.test.js +124 -79
  45. package/pi-extension/tests/integration/unaffected-regressions.test.js +411 -0
  46. package/runtime/prompts/cognitive-routing.md +5 -4
  47. package/runtime/prompts/conversation-history.md +1 -1
  48. package/runtime/prompts/core.md +77 -6
  49. package/runtime/prompts/interaction-contract.md +6 -2
  50. package/skills/action-selection/SKILL.md +93 -44
  51. package/skills/action-selection/references/trajectory-stalls.md +71 -0
  52. package/skills/bypass/SKILL.md +109 -39
  53. package/skills/commit-work/SKILL.md +94 -55
  54. package/skills/commit-work/references/git-state-edges.md +94 -0
  55. package/skills/commit-work/references/simple-push.md +92 -0
  56. package/skills/commit-work/references/staging-decisions.md +79 -46
  57. package/skills/decision-gate/SKILL.md +80 -22
  58. package/skills/design-for-depth/SKILL.md +208 -43
  59. package/skills/design-for-depth/references/design-pressure-signals.md +108 -240
  60. package/skills/design-for-depth/references/interface-design-loop.md +77 -97
  61. package/skills/design-for-depth/references/module-and-dependency-design.md +147 -0
  62. package/skills/design-for-depth/references/software-design-philosophy.md +127 -173
  63. package/skills/design-for-depth/references/state-and-failure-boundaries.md +136 -0
  64. package/skills/diagnose-failure/SKILL.md +198 -52
  65. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +19 -5
  66. package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +13 -5
  67. package/skills/discuss/SKILL.md +118 -76
  68. package/skills/discuss/references/discussion-continuity.md +84 -32
  69. package/skills/evaluate-skill/SKILL.md +166 -52
  70. package/skills/evaluate-skill/references/evaluation-definition-schema.md +2 -2
  71. package/skills/evaluate-skill/references/evaluation-design.md +56 -30
  72. package/skills/evaluate-skill/references/execution-and-evidence.md +1 -1
  73. package/skills/evaluate-skill/references/review-and-revision.md +62 -21
  74. package/skills/execute-work/SKILL.md +98 -59
  75. package/skills/execute-work/references/code-practices.md +4 -4
  76. package/skills/execute-work/references/execute-work-edges.md +42 -22
  77. package/skills/review-artifact/SKILL.md +132 -71
  78. package/skills/review-artifact/references/adjudicate-artifact-review.md +101 -0
  79. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +52 -41
  80. package/skills/review-work/SKILL.md +115 -72
  81. package/skills/review-work/references/adjudicate-work-review.md +97 -0
  82. package/skills/review-work/references/independent-work-reviewer-contract.md +40 -35
  83. package/skills/review-work/references/security-risk-lens.md +17 -15
  84. package/skills/setup-freeflow/SKILL.md +14 -17
  85. package/skills/setup-freeflow/references/activation-contract.md +24 -30
  86. package/skills/setup-freeflow/references/host-setup.md +6 -7
  87. package/skills/simplify-code/SKILL.md +97 -39
  88. package/skills/simplify-code/references/simplification-patterns.md +1 -1
  89. package/skills/tdd/SKILL.md +108 -41
  90. package/skills/tdd/references/test-design.md +1 -1
  91. package/skills/track-work/SKILL.md +133 -300
  92. package/skills/track-work/references/working-record-format.md +515 -0
  93. package/skills/track-work/scripts/lib/document.mjs +713 -0
  94. package/skills/track-work/scripts/lib/format.mjs +166 -0
  95. package/skills/track-work/scripts/lib/store.mjs +233 -0
  96. package/skills/track-work/scripts/lib/transitions.mjs +790 -0
  97. package/skills/track-work/scripts/lib/views.mjs +27 -430
  98. package/skills/track-work/scripts/working-record.mjs +292 -98
  99. package/skills/verify-work/SKILL.md +46 -20
  100. package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
  101. package/skills/verify-work/references/integration-evidence.md +1 -7
  102. package/skills/verify-work/references/performance-evidence.md +1 -1
  103. package/skills/workflow/SKILL.md +110 -80
  104. package/skills/workflow/references/domain-skill-composition.md +24 -18
  105. package/skills/write-skill/SKILL.md +218 -62
  106. package/skills/write-skill/references/activation-boundaries.md +63 -21
  107. package/skills/write-skill/references/agent-first-instructions.md +61 -27
  108. package/skills/write-skill/references/progressive-disclosure.md +91 -41
  109. package/skills/write-skill/references/skill-dependency-graphs.md +190 -0
  110. package/runtime/prompts/skills.md +0 -65
  111. package/skills/mode-contract/SKILL.md +0 -104
  112. package/skills/track-work/scripts/lib/codec.mjs +0 -570
  113. package/skills/track-work/scripts/lib/commands.mjs +0 -568
  114. package/skills/track-work/scripts/lib/contract.mjs +0 -303
  115. package/skills/track-work/scripts/lib/model.mjs +0 -506
  116. package/skills/track-work/scripts/lib/operations.mjs +0 -965
  117. package/skills/track-work/scripts/lib/record-store.mjs +0 -264
  118. package/skills/track-work/scripts/lib/result.mjs +0 -37
  119. package/skills/track-work/scripts/lib/rewrites.mjs +0 -740
  120. package/skills/track-work/scripts/lib/schema.mjs +0 -277
  121. package/skills/track-work/scripts/lib/source-inventory.mjs +0 -162
  122. package/skills/track-work/scripts/lib/workspace.mjs +0 -134
@@ -3,35 +3,19 @@ import { appendFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, join, resolve } from "node:path";
4
4
  import { promisify } from "node:util";
5
5
  import {
6
- handleModeCommand,
7
6
  readCapabilityState,
8
7
  readFreeflowConfig,
9
8
  readFreeflowConfigLayers,
10
9
  readFreeflowLocalConfig,
11
- readModeState,
12
10
  resetSessionOverrides,
13
11
  setSessionCoreOverride,
14
- VALID_MODES,
15
12
  } from "../runtime/runtime-context.js";
16
13
  import { PiSettingsComponent } from "./settings-tui.js";
14
+ import { supportsPiSessionModelStateApi } from "../cognitive-routing/pi-session-control.js";
17
15
  import { isPiFlowHost } from "../runtime/runtime-identity.js";
18
16
  const DEFAULT_FREEFLOW_ENABLED = true;
19
- const DEFAULT_INTERACTION_CONTRACT_ENABLED = true;
20
- const DEFAULT_SKILLS_ENABLED = true;
21
17
  const DEFAULT_CONTEXT_VIRTUALIZATION_ENABLED = false;
22
18
  const DEFAULT_CONVERSATION_HISTORY_ENABLED = false;
23
- const MODE_VALUES = ["conversation", "workflow", "strict-workflow"];
24
- const MODE_LABELS = {
25
- default: "Use configured default",
26
- conversation: "conversation",
27
- workflow: "workflow",
28
- "strict-workflow": "strict-workflow",
29
- };
30
- const MODE_DESCRIPTIONS = {
31
- conversation: "Discussion and read-only inspection",
32
- workflow: "Adaptive workflow for consequential work",
33
- "strict-workflow": "Stronger decision and evidence pressure for high-risk work",
34
- };
35
19
  const LOCAL_INHERIT = "inherit";
36
20
  const execFileAsync = promisify(execFile);
37
21
  function isRecord(value) {
@@ -208,83 +192,18 @@ function createScopedBooleanItem(options) {
208
192
  item.displaySuffix = coreDisplaySuffix(item);
209
193
  return item;
210
194
  }
211
- function createScopedDefaultModeItem(options) {
212
- let item;
213
- if (options.scope === "local") {
214
- item = {
215
- id: "freeflow.defaultMode",
216
- label: "Default mode",
217
- description:
218
- "Personal default mode for this checkout. Choose inherit to use the repository default; use /freeflow settings repo to edit shared defaults.",
219
- path: ["defaultMode"],
220
- kind: "enum",
221
- value: options.localDefaultMode ?? LOCAL_INHERIT,
222
- values: [LOCAL_INHERIT, ...MODE_VALUES],
223
- valueLabels: {
224
- inherit: "Inherit repository",
225
- ...MODE_LABELS,
226
- },
227
- valueDescriptions: {
228
- inherit: `Use ${options.repositoryDefaultMode} from ${options.repositoryDefaultSource}.`,
229
- ...MODE_DESCRIPTIONS,
230
- },
231
- format: (value) => String(value),
232
- configScope: "local",
233
- configValues: { inherit: undefined },
234
- effectiveValue: options.effectiveValue,
235
- effectiveSource: options.effectiveSource,
236
- inheritedValue: options.repositoryDefaultMode,
237
- inheritedSource: options.repositoryDefaultSource,
238
- };
239
- } else {
240
- item = {
241
- id: "freeflow.defaultMode",
242
- label: "Default mode",
243
- description:
244
- "Shared repository default Freeflow mode used when Skills are enabled. This edits .freeflow/config.json.",
245
- path: ["defaultMode"],
246
- kind: "enum",
247
- value: options.repositoryDefaultMode,
248
- values: MODE_VALUES,
249
- valueLabels: MODE_LABELS,
250
- valueDescriptions: MODE_DESCRIPTIONS,
251
- configScope: "repository",
252
- effectiveValue: options.effectiveValue,
253
- effectiveSource: options.effectiveSource,
254
- localOverrideValue: options.localDefaultMode,
255
- };
256
- }
257
- item.displaySuffix = coreDisplaySuffix(item);
258
- return item;
259
- }
260
- function sessionModeDisplaySuffix(sessionMode, defaultMode, defaultSource, inactive) {
261
- if (sessionMode !== "default") return undefined;
262
- const inactiveSuffix = inactive ? " · inactive" : "";
263
- return `(${defaultMode} · ${defaultSource}${inactiveSuffix})`;
264
- }
265
- function validModeOrUndefined(value) {
266
- return typeof value === "string" && VALID_MODES.has(value) ? value : undefined;
267
- }
268
195
  function resolveSettingsCoreView(rawConfig, layers) {
269
196
  const localConfig = layers?.local.valid && isRecord(layers.local.parsed) ? layers.local.parsed : {};
270
- const repositorySkillsValue = getPath(rawConfig, ["skills"]);
271
- const repositorySkills = isRecord(repositorySkillsValue) ? repositorySkillsValue : {};
272
197
  const fallbackCore = {
273
198
  enabled: getPath(rawConfig, ["enabled"]) !== false,
274
- interactionContract: getPath(rawConfig, ["interactionContract"]) !== false,
275
199
  contextVirtualization: getPath(rawConfig, ["contextVirtualization"]) === true,
276
200
  conversationHistory: getPath(rawConfig, ["conversationHistory"]) === true,
277
- skills: { enabled: getPath(repositorySkills, ["enabled"]) !== false },
278
- defaultMode: validModeOrUndefined(rawConfig.defaultMode) ?? "workflow",
279
201
  };
280
202
  const fallbackSources = {
281
203
  enabled: typeof getPath(rawConfig, ["enabled"]) === "boolean" ? "repository" : "builtin",
282
- interactionContract: typeof getPath(rawConfig, ["interactionContract"]) === "boolean" ? "repository" : "builtin",
283
204
  contextVirtualization:
284
205
  typeof getPath(rawConfig, ["contextVirtualization"]) === "boolean" ? "repository" : "builtin",
285
206
  conversationHistory: typeof getPath(rawConfig, ["conversationHistory"]) === "boolean" ? "repository" : "builtin",
286
- skillsEnabled: typeof getPath(repositorySkills, ["enabled"]) === "boolean" ? "repository" : "builtin",
287
- defaultMode: validModeOrUndefined(rawConfig.defaultMode) === undefined ? "builtin" : "repository",
288
207
  };
289
208
  return {
290
209
  localConfig,
@@ -329,7 +248,7 @@ function createSessionBooleanItem(options) {
329
248
  item.displaySuffix = coreDisplaySuffix(item);
330
249
  return item;
331
250
  }
332
- function sessionFreeflowItems(state, modeState, cognitiveRoutingController) {
251
+ function sessionFreeflowItems(state, cognitiveRoutingController) {
333
252
  const sessionOverrides = state.sessionOverrides;
334
253
  const configured = state.configuredCoreConfig;
335
254
  const configuredSources = state.configuredSources;
@@ -345,28 +264,6 @@ function sessionFreeflowItems(state, modeState, cognitiveRoutingController) {
345
264
  effectiveSource: effectiveSources.enabled,
346
265
  sessionOverrides,
347
266
  });
348
- const interactionItem = createSessionBooleanItem({
349
- id: "freeflow.interactionContract",
350
- label: "Interaction Contract",
351
- description: "Temporary Interaction Contract override for this Pi session.",
352
- key: "interactionContract",
353
- inheritedValue: configured.interactionContract,
354
- inheritedSource: configuredSources.interactionContract,
355
- effectiveValue: state.interactionContract.enabled,
356
- effectiveSource: effectiveSources.interactionContract,
357
- sessionOverrides,
358
- });
359
- const skillsItem = createSessionBooleanItem({
360
- id: "freeflow.skills.enabled",
361
- label: "Skills",
362
- description: "Temporary Freeflow Skills override for this Pi session.",
363
- key: "skillsEnabled",
364
- inheritedValue: configured.skills.enabled,
365
- inheritedSource: configuredSources.skillsEnabled,
366
- effectiveValue: state.skills.enabled,
367
- effectiveSource: effectiveSources.skillsEnabled,
368
- sessionOverrides,
369
- });
370
267
  const contextVirtualizationItem = createSessionBooleanItem({
371
268
  id: "freeflow.contextVirtualization",
372
269
  label: "Context Virtualization",
@@ -390,37 +287,8 @@ function sessionFreeflowItems(state, modeState, cognitiveRoutingController) {
390
287
  sessionOverrides,
391
288
  });
392
289
  const freeflowInactive = !state.enabled;
393
- const skillsEnabled = state.skills.enabled;
394
- interactionItem.inactive = freeflowInactive;
395
- skillsItem.inactive = freeflowInactive;
396
- contextVirtualizationItem.inactive = freeflowInactive || !skillsEnabled;
397
- conversationHistoryItem.inactive = freeflowInactive || !skillsEnabled;
398
- const sessionMode = modeState.currentMode ?? "default";
399
- const sessionModeItem = {
400
- id: "freeflow.sessionMode",
401
- label: "Mode",
402
- description: "Temporary mode override for this Pi session.",
403
- kind: "enum",
404
- value: sessionMode,
405
- values: ["default", ...MODE_VALUES],
406
- valueLabels: {
407
- ...MODE_LABELS,
408
- default: "Use configured default",
409
- },
410
- valueDescriptions: {
411
- default: `${modeState.defaultMode} from ${modeState.defaultModeSource}`,
412
- ...MODE_DESCRIPTIONS,
413
- },
414
- inactive: freeflowInactive || !skillsEnabled,
415
- displaySuffix: sessionModeDisplaySuffix(
416
- sessionMode,
417
- modeState.defaultMode,
418
- modeState.defaultModeSource,
419
- freeflowInactive || !skillsEnabled,
420
- ),
421
- inheritedValue: modeState.defaultMode,
422
- inheritedSource: modeState.defaultModeSource,
423
- };
290
+ contextVirtualizationItem.inactive = freeflowInactive;
291
+ conversationHistoryItem.inactive = freeflowInactive;
424
292
  const cognitiveRoutingState = cognitiveRoutingController?.state();
425
293
  const cognitiveRoutingProfile =
426
294
  cognitiveRoutingState?.controlMode === "manual-standard"
@@ -446,22 +314,18 @@ function sessionFreeflowItems(state, modeState, cognitiveRoutingController) {
446
314
  standard: "Hold the standard profile until /freeflow profile auto.",
447
315
  reasoning: "Hold the reasoning profile until /freeflow profile auto.",
448
316
  },
449
- inactive: !state.cognitiveRouting.effective || cognitiveRoutingController === undefined,
317
+ inactive: freeflowInactive || !state.cognitiveRouting.effective || cognitiveRoutingController === undefined,
450
318
  runtimeInactive: state.cognitiveRouting.blockingReason?.code === "runtime_disabled",
451
319
  displaySuffix: cognitiveRoutingState?.effective ? cognitiveRoutingProfile : "unavailable",
452
320
  }
453
321
  : undefined;
454
322
  return [
455
323
  freeflowItem,
456
- interactionItem,
457
- skillsItem,
458
- sessionModeItem,
459
324
  ...(cognitiveRoutingItem ? [cognitiveRoutingItem] : []),
460
325
  {
461
326
  id: "freeflow.session.reset",
462
327
  label: "Reset session overrides",
463
- description:
464
- "Clear Freeflow, Interaction Contract, Skills, Context Virtualization, Conversation History, and mode overrides for this Pi session.",
328
+ description: "Clear Freeflow, Context Virtualization, and Conversation History overrides for this Pi session.",
465
329
  kind: "enum",
466
330
  value: "available",
467
331
  values: ["reset"],
@@ -688,18 +552,18 @@ function cognitiveRoutingProfileItem(options) {
688
552
  }
689
553
  function cognitiveRoutingSessionStartItem(options) {
690
554
  const path = ["cognitiveRouting", "sessionStart", options.setting];
691
- const defaultValue = options.setting === "control" ? "automatic" : "standard";
555
+ const defaultValue = options.setting === "control" ? "automatic" : "reasoning";
692
556
  const values = options.setting === "control" ? ["automatic", "manual"] : ["standard", "reasoning"];
693
557
  const labels = Object.fromEntries(values.map((value) => [value, value]));
694
558
  const descriptions =
695
559
  options.setting === "control"
696
560
  ? {
697
- automatic: "Let Cognitive Routing manage profile transitions for the new session.",
561
+ automatic: "Start the new session in Reasoning; automatic delegation may use Standard during execution.",
698
562
  manual: "Hold the selected profile for the new session until the user changes it.",
699
563
  }
700
564
  : {
701
- standard: "Start a new session with the configured Standard preset.",
702
- reasoning: "Start a new session with the configured Reasoning preset.",
565
+ standard: "Start a new manual session with the configured Standard preset.",
566
+ reasoning: "Start a new manual session with the configured Reasoning preset.",
703
567
  };
704
568
  const repositoryValue = getPath(options.rawConfig, path);
705
569
  const localValue = getPath(options.localConfig, path);
@@ -710,13 +574,21 @@ function cognitiveRoutingSessionStartItem(options) {
710
574
  const inheritedSource = repositorySetting ? "repository" : "builtin";
711
575
  const configuredSource =
712
576
  options.capabilityState?.sessionStartSources?.[options.setting] ?? (repositorySetting ? "repository" : undefined);
713
- const effectiveValue = options.capabilityState?.sessionStart?.[options.setting] ?? inheritedValue;
577
+ const effectiveSessionStartControl =
578
+ options.capabilityState?.sessionStart?.control ??
579
+ getPath(options.localConfig, ["cognitiveRouting", "sessionStart", "control"]) ??
580
+ getPath(options.rawConfig, ["cognitiveRouting", "sessionStart", "control"]) ??
581
+ "automatic";
582
+ const effectiveValue =
583
+ options.setting === "profile" && effectiveSessionStartControl === "automatic"
584
+ ? "reasoning"
585
+ : (options.capabilityState?.sessionStart?.[options.setting] ?? inheritedValue);
714
586
  const effectiveSource = cognitiveRoutingSettingsSource(configuredSource);
715
- const label = options.setting === "control" ? "Session start control" : "Session start profile";
587
+ const label = options.setting === "control" ? "Session start control" : "Manual session-start profile";
716
588
  const description =
717
589
  options.setting === "control"
718
590
  ? "Choose automatic or manual control for new sessions only; changing this does not alter the active session."
719
- : "Choose the initial profile for new sessions only; changing this does not alter the active session.";
591
+ : "Choose the profile for manual session starts; automatic sessions always start in Reasoning.";
720
592
  const item =
721
593
  options.scope === "local"
722
594
  ? {
@@ -760,7 +632,10 @@ function cognitiveRoutingSessionStartItem(options) {
760
632
  item.displaySuffix = coreDisplaySuffix(item);
761
633
  return item;
762
634
  }
763
- function freeflowItems(rawConfig, modeState, options = {}) {
635
+ function isCognitiveRoutingRuntimeAvailable(pi) {
636
+ return isPiFlowHost(pi?.host) || supportsPiSessionModelStateApi(pi);
637
+ }
638
+ function freeflowItems(rawConfig, options = {}) {
764
639
  const scope = options.scope ?? "repository";
765
640
  const layers = options.layers;
766
641
  const { localConfig, core, sources } = resolveSettingsCoreView(rawConfig, layers);
@@ -770,36 +645,12 @@ function freeflowItems(rawConfig, modeState, options = {}) {
770
645
  localConfig,
771
646
  id: "freeflow.enabled",
772
647
  label: "Freeflow",
773
- description: "Master switch for the Interaction Contract and Freeflow skills in this checkout.",
648
+ description: "Master switch for Freeflow's core guidance, skills, and optional capabilities in this checkout.",
774
649
  path: ["enabled"],
775
650
  effectiveValue: core.enabled,
776
651
  effectiveSource: sources.enabled,
777
652
  defaultValue: DEFAULT_FREEFLOW_ENABLED,
778
653
  });
779
- const interactionItem = createScopedBooleanItem({
780
- scope,
781
- rawConfig,
782
- localConfig,
783
- id: "freeflow.interactionContract",
784
- label: "Interaction Contract",
785
- description: "Apply Freeflow's compact turn-interpretation and collaboration guidance.",
786
- path: ["interactionContract"],
787
- effectiveValue: core.interactionContract,
788
- effectiveSource: sources.interactionContract,
789
- defaultValue: DEFAULT_INTERACTION_CONTRACT_ENABLED,
790
- });
791
- const skillsItem = createScopedBooleanItem({
792
- scope,
793
- rawConfig,
794
- localConfig,
795
- id: "freeflow.skills.enabled",
796
- label: "Skills",
797
- description: "Expose Freeflow skills and discover Workflow before consequential or mutating work.",
798
- path: ["skills", "enabled"],
799
- effectiveValue: core.skills.enabled,
800
- effectiveSource: sources.skillsEnabled,
801
- defaultValue: DEFAULT_SKILLS_ENABLED,
802
- });
803
654
  const contextVirtualizationItem = createScopedBooleanItem({
804
655
  scope,
805
656
  rawConfig,
@@ -824,53 +675,11 @@ function freeflowItems(rawConfig, modeState, options = {}) {
824
675
  effectiveSource: sources.conversationHistory,
825
676
  defaultValue: DEFAULT_CONVERSATION_HISTORY_ENABLED,
826
677
  });
827
- const repositoryModeValue = validModeOrUndefined(rawConfig.defaultMode);
828
- const repositoryDefaultMode = repositoryModeValue ?? "workflow";
829
- const repositoryDefaultSource = repositoryModeValue ? "repository" : "builtin";
830
- const localDefaultMode = validModeOrUndefined(localConfig.defaultMode);
831
- const defaultModeItem = createScopedDefaultModeItem({
832
- scope,
833
- repositoryDefaultMode,
834
- repositoryDefaultSource,
835
- localDefaultMode,
836
- effectiveValue: core.defaultMode,
837
- effectiveSource: sources.defaultMode,
838
- });
839
678
  const freeflowInactive = !core.enabled;
840
- const skillsEnabled = core.skills.enabled;
841
- interactionItem.inactive = freeflowInactive;
842
- skillsItem.inactive = freeflowInactive;
843
- contextVirtualizationItem.inactive = freeflowInactive || !skillsEnabled;
844
- conversationHistoryItem.inactive = freeflowInactive || !skillsEnabled;
845
- defaultModeItem.inactive = freeflowInactive;
846
- defaultModeItem.displaySuffix = coreDisplaySuffix(defaultModeItem, freeflowInactive || !skillsEnabled);
847
- const sessionMode = modeState?.currentMode ?? "default";
848
- const sessionModeItem = {
849
- id: "freeflow.sessionMode",
850
- label: "Session mode",
851
- description:
852
- "Temporary mode override for this Pi session. Use configured default clears the override without changing either config file.",
853
- kind: "enum",
854
- value: sessionMode,
855
- values: ["default", ...MODE_VALUES],
856
- valueLabels: {
857
- ...MODE_LABELS,
858
- default: "Use configured default",
859
- },
860
- valueDescriptions: {
861
- default: `${core.defaultMode} from ${sources.defaultMode}`,
862
- ...MODE_DESCRIPTIONS,
863
- },
864
- inactive: freeflowInactive || !skillsEnabled,
865
- displaySuffix: sessionModeDisplaySuffix(
866
- sessionMode,
867
- core.defaultMode,
868
- sources.defaultMode,
869
- freeflowInactive || !skillsEnabled,
870
- ),
871
- };
679
+ contextVirtualizationItem.inactive = freeflowInactive;
680
+ conversationHistoryItem.inactive = freeflowInactive;
872
681
  const cognitiveRoutingState = options.cognitiveRouting;
873
- const cognitiveRoutingRuntimeDisabled = !isPiFlowHost(options.hostInfo);
682
+ const cognitiveRoutingRuntimeDisabled = options.runtimeAvailable !== true;
874
683
  const cognitiveRoutingGroup = (() => {
875
684
  const cognitiveRoutingEnabledItem = createScopedBooleanItem({
876
685
  scope,
@@ -879,14 +688,14 @@ function freeflowItems(rawConfig, modeState, options = {}) {
879
688
  id: "freeflow.cognitiveRouting.enabled",
880
689
  label: "Enabled",
881
690
  description: cognitiveRoutingRuntimeDisabled
882
- ? "Configured for PiFlow, but disabled in normal Pi."
691
+ ? "Requires a host model-state control API; configuration is read-only on this host."
883
692
  : "Allow Cognitive Routing to own the session model lease and switch the configured profiles.",
884
693
  path: ["cognitiveRouting", "enabled"],
885
694
  effectiveValue: cognitiveRoutingState?.enabled ?? false,
886
695
  effectiveSource: cognitiveRoutingSettingsSource(cognitiveRoutingState?.enabledSource),
887
696
  defaultValue: false,
888
697
  });
889
- cognitiveRoutingEnabledItem.inactive = freeflowInactive || !skillsEnabled || cognitiveRoutingRuntimeDisabled;
698
+ cognitiveRoutingEnabledItem.inactive = freeflowInactive || cognitiveRoutingRuntimeDisabled;
890
699
  cognitiveRoutingEnabledItem.runtimeInactive = cognitiveRoutingRuntimeDisabled;
891
700
  const cognitiveRoutingProfiles = ["standard", "reasoning"].map((name) =>
892
701
  cognitiveRoutingProfileItem({
@@ -908,11 +717,11 @@ function freeflowItems(rawConfig, modeState, options = {}) {
908
717
  }),
909
718
  );
910
719
  for (const item of [...cognitiveRoutingProfiles, ...cognitiveRoutingSessionStart]) {
911
- item.inactive ||= freeflowInactive || !skillsEnabled || cognitiveRoutingRuntimeDisabled;
720
+ item.inactive ||= freeflowInactive || cognitiveRoutingRuntimeDisabled;
912
721
  item.runtimeInactive = cognitiveRoutingRuntimeDisabled;
913
722
  }
914
723
  const cognitiveRoutingStatus = cognitiveRoutingRuntimeDisabled
915
- ? "disabled · PiFlow only"
724
+ ? "unavailable · host unsupported"
916
725
  : cognitiveRoutingState
917
726
  ? cognitiveRoutingState.effective
918
727
  ? "active"
@@ -924,21 +733,17 @@ function freeflowItems(rawConfig, modeState, options = {}) {
924
733
  id: "freeflow.cognitiveRouting",
925
734
  label: "Cognitive Routing",
926
735
  description: cognitiveRoutingRuntimeDisabled
927
- ? "Cognitive Routing configuration is visible for inspection but can only run in PiFlow."
928
- : "Configure the automatic standard/reasoning profiles and choose whether Freeflow may manage model state for this repository.",
736
+ ? "Cognitive Routing configuration is visible for inspection but requires a host model-state control API."
737
+ : "Configure the Standard and Reasoning profiles and choose whether Freeflow may manage model state for this repository.",
929
738
  kind: "group",
930
739
  value: cognitiveRoutingRuntimeDisabled ? false : (cognitiveRoutingState?.enabled ?? false),
931
- inactive: freeflowInactive || !skillsEnabled,
740
+ inactive: freeflowInactive,
932
741
  displaySuffix: cognitiveRoutingStatus,
933
742
  children: [cognitiveRoutingEnabledItem, ...cognitiveRoutingProfiles, ...cognitiveRoutingSessionStart],
934
743
  };
935
744
  })();
936
745
  return [
937
746
  freeflowItem,
938
- interactionItem,
939
- skillsItem,
940
- sessionModeItem,
941
- defaultModeItem,
942
747
  ...(cognitiveRoutingGroup ? [cognitiveRoutingGroup] : []),
943
748
  {
944
749
  id: "freeflow.context",
@@ -954,8 +759,7 @@ function freeflowItems(rawConfig, modeState, options = {}) {
954
759
  function pruneKnownDefaults(config) {
955
760
  const defaultPaths = [
956
761
  { path: ["enabled"], value: DEFAULT_FREEFLOW_ENABLED },
957
- { path: ["interactionContract"], value: DEFAULT_INTERACTION_CONTRACT_ENABLED },
958
- { path: ["skills", "enabled"], value: DEFAULT_SKILLS_ENABLED },
762
+ { path: ["contextVirtualization"], value: DEFAULT_CONTEXT_VIRTUALIZATION_ENABLED },
959
763
  { path: ["conversationHistory"], value: DEFAULT_CONVERSATION_HISTORY_ENABLED },
960
764
  ];
961
765
  for (const item of defaultPaths) {
@@ -1068,33 +872,12 @@ function findSettingsItem(items, id) {
1068
872
  function refreshSettingsDerivedState(items) {
1069
873
  const freeflowItem = findSettingsItem(items, "freeflow.enabled");
1070
874
  const freeflowInactive = freeflowItem ? effectiveItemValue(freeflowItem) !== true : false;
1071
- const skillsItem = findSettingsItem(items, "freeflow.skills.enabled");
1072
- const skillsEnabled = skillsItem ? effectiveItemValue(skillsItem) === true : true;
1073
- const sessionModeItem = findSettingsItem(items, "freeflow.sessionMode");
1074
- const defaultModeItem = findSettingsItem(items, "freeflow.defaultMode");
1075
875
  const cognitiveRoutingGroup = findSettingsItem(items, "freeflow.cognitiveRouting");
1076
876
  const cognitiveRoutingEnabledItem = findSettingsItem(items, "freeflow.cognitiveRouting.enabled");
1077
877
  const cognitiveRoutingProfiles = [
1078
878
  findSettingsItem(items, "freeflow.cognitiveRouting.standard"),
1079
879
  findSettingsItem(items, "freeflow.cognitiveRouting.reasoning"),
1080
880
  ];
1081
- if (sessionModeItem) {
1082
- const defaultMode = String(
1083
- defaultModeItem ? effectiveItemValue(defaultModeItem) : (sessionModeItem.inheritedValue ?? "workflow"),
1084
- );
1085
- const defaultSource = defaultModeItem?.effectiveSource ?? sessionModeItem.inheritedSource ?? "builtin";
1086
- sessionModeItem.inactive = freeflowInactive || !skillsEnabled;
1087
- sessionModeItem.displaySuffix = sessionModeDisplaySuffix(
1088
- String(sessionModeItem.value),
1089
- defaultMode,
1090
- defaultSource,
1091
- freeflowInactive || !skillsEnabled,
1092
- );
1093
- sessionModeItem.valueDescriptions = {
1094
- default: `${defaultMode} from ${defaultSource}`,
1095
- ...MODE_DESCRIPTIONS,
1096
- };
1097
- }
1098
881
  if (cognitiveRoutingGroup && cognitiveRoutingEnabledItem) {
1099
882
  const enabled = effectiveItemValue(cognitiveRoutingEnabledItem) === true;
1100
883
  const profilesConfigured = cognitiveRoutingProfiles.every((item) =>
@@ -1108,7 +891,7 @@ function refreshSettingsDerivedState(items) {
1108
891
  : "configured"
1109
892
  : "not configured"
1110
893
  : "disabled";
1111
- cognitiveRoutingGroup.inactive = freeflowInactive || !skillsEnabled;
894
+ cognitiveRoutingGroup.inactive = freeflowInactive;
1112
895
  }
1113
896
  const contextGroup = findSettingsItem(items, "freeflow.context");
1114
897
  if (contextGroup?.children?.length) {
@@ -1121,31 +904,11 @@ function refreshSettingsDerivedState(items) {
1121
904
  candidate.inactive = false;
1122
905
  } else if (candidate.configScope) {
1123
906
  const inactive =
1124
- candidate.id === "freeflow.enabled"
1125
- ? false
1126
- : candidate.runtimeInactive === true ||
1127
- freeflowInactive ||
1128
- (!skillsEnabled &&
1129
- [
1130
- "freeflow.cognitiveRouting",
1131
- "freeflow.cognitiveRouting.enabled",
1132
- "freeflow.cognitiveRouting.standard",
1133
- "freeflow.cognitiveRouting.reasoning",
1134
- "freeflow.cognitiveRouting.sessionStart.control",
1135
- "freeflow.cognitiveRouting.sessionStart.profile",
1136
- "freeflow.contextVirtualization",
1137
- "freeflow.conversationHistory",
1138
- ].includes(candidate.id));
1139
- const displayInactive = candidate.id === "freeflow.defaultMode" ? freeflowInactive || !skillsEnabled : inactive;
907
+ candidate.id === "freeflow.enabled" ? false : candidate.runtimeInactive === true || freeflowInactive;
1140
908
  candidate.inactive = inactive;
1141
- candidate.displaySuffix = coreDisplaySuffix(candidate, displayInactive);
1142
- } else if (candidate.id === "freeflow.sessionMode") {
1143
- candidate.inactive = candidate.runtimeInactive === true || freeflowInactive || !skillsEnabled;
909
+ candidate.displaySuffix = coreDisplaySuffix(candidate, inactive);
1144
910
  } else {
1145
- candidate.inactive =
1146
- candidate.runtimeInactive === true ||
1147
- freeflowInactive ||
1148
- (!skillsEnabled && candidate.id === "freeflow.cognitiveRouting");
911
+ candidate.inactive = candidate.runtimeInactive === true || freeflowInactive;
1149
912
  }
1150
913
  });
1151
914
  }
@@ -1251,7 +1014,7 @@ function freeflowStatusText(state, cognitiveRoutingController) {
1251
1014
  const cognitiveRouting = state.cognitiveRouting;
1252
1015
  const cognitiveRoutingStatus = cognitiveRouting
1253
1016
  ? cognitiveRouting.blockingReason?.code === "runtime_disabled"
1254
- ? "disabled (PiFlow only)"
1017
+ ? "unavailable (host unsupported)"
1255
1018
  : cognitiveRouting.effective
1256
1019
  ? routingState?.effective
1257
1020
  ? `active (${routingState.activeProfile ?? "unknown"}, ${routingState.controlMode})`
@@ -1263,16 +1026,12 @@ function freeflowStatusText(state, cognitiveRoutingController) {
1263
1026
  const contextEnabled = state.contextVirtualization?.effective || state.conversationHistory?.effective;
1264
1027
  return [
1265
1028
  `Freeflow: ${state.enabled ? "enabled" : "disabled"}${sessionSuffix(state.configSources.enabled)}`,
1266
- `interaction contract: ${state.interactionContract.effective ? "enabled" : "disabled"}${sessionSuffix(state.configSources.interactionContract)}`,
1267
- `skills: ${state.skills.effective ? "enabled" : "disabled (workflow modes inactive)"}${sessionSuffix(state.configSources.skillsEnabled)}`,
1268
1029
  `context: ${contextEnabled ? "enabled" : "disabled"} (virtualization ${state.contextVirtualization?.effective ? "enabled" : "disabled"}, history ${state.conversationHistory?.effective ? "enabled" : "disabled"})`,
1269
1030
  ...(cognitiveRoutingStatus ? [`cognitive routing: ${cognitiveRoutingStatus}`] : []),
1270
1031
  ].join("; ");
1271
1032
  }
1272
1033
  const NON_TUI_SETTINGS_GUIDANCE =
1273
- "Freeflow settings require Pi TUI mode. Use /freeflow status to inspect current state; supported non-TUI changes are /freeflow enable, /freeflow disable, and /freeflow mode <conversation|workflow|strict-workflow|reset>.";
1274
- const NON_TUI_MODE_GUIDANCE =
1275
- "Freeflow mode selector requires Pi TUI mode. Use /freeflow mode conversation, /freeflow mode workflow, /freeflow mode strict-workflow, or /freeflow mode reset.";
1034
+ "Freeflow settings require Pi TUI mode. Use /freeflow status to inspect current state; supported non-TUI changes are /freeflow enable and /freeflow disable.";
1276
1035
  function ensureSettingsIdle(ctx) {
1277
1036
  if (typeof ctx?.isIdle !== "function" || ctx.isIdle()) return true;
1278
1037
  ctx.ui?.notify?.("Freeflow settings and profile changes are available only while Pi is idle.", "warning");
@@ -1323,19 +1082,15 @@ export async function handleFreeflowCommand(args, ctx, afterChange, pi, cognitiv
1323
1082
  const [action, ...rest] = input.split(/\s+/);
1324
1083
  const actionValue = rest.join(" ");
1325
1084
  const nonTui = ctx?.mode && ctx.mode !== "tui";
1326
- if (nonTui && action === "mode" && !actionValue) {
1327
- return nonTuiGuidance(ctx, NON_TUI_MODE_GUIDANCE);
1328
- }
1329
1085
  const settingsSelector =
1330
1086
  action === "settings" &&
1331
1087
  (!actionValue || ["session", "local", "personal", "repo", "repository", "shared"].includes(actionValue));
1332
1088
  if (nonTui && settingsSelector) {
1333
1089
  return nonTuiGuidance(ctx, NON_TUI_SETTINGS_GUIDANCE);
1334
1090
  }
1335
- const [layers, state, modeState] = await Promise.all([
1091
+ const [layers, state] = await Promise.all([
1336
1092
  readFreeflowConfigLayers(ctx.cwd),
1337
1093
  readCapabilityState(ctx.cwd, ctx, pi?.host),
1338
- readModeState(ctx.cwd),
1339
1094
  ]);
1340
1095
  const configState = layers.repository;
1341
1096
  const raw = configState.valid ? configState.parsed : {};
@@ -1354,48 +1109,15 @@ export async function handleFreeflowCommand(args, ctx, afterChange, pi, cognitiv
1354
1109
  );
1355
1110
  return { changed: false, reloaded: false, error: "invalid_local_config" };
1356
1111
  }
1357
- if (action === "mode") {
1358
- if (!ensureSettingsIdle(ctx)) return { changed: false, reloaded: false, error: "busy" };
1359
- if (actionValue) {
1360
- const result = await handleModeCommand(actionValue, ctx, pi);
1361
- return { changed: result.changed, reloaded: false, error: result.error };
1362
- }
1363
- if (!state.enabled || !state.skills.effective) {
1364
- const result = await handleModeCommand(undefined, ctx, pi);
1365
- return { changed: false, reloaded: false, error: result.error };
1366
- }
1367
- if (typeof ctx?.ui?.custom !== "function") {
1368
- const result = await handleModeCommand(undefined, ctx, pi);
1369
- return { changed: false, reloaded: false, error: result.error };
1370
- }
1371
- const item = freeflowItems(raw, modeState, {
1372
- scope: "local",
1373
- layers,
1374
- cognitiveRouting: state.cognitiveRouting,
1375
- ctx,
1376
- hostInfo: pi?.host,
1377
- }).find((candidate) => candidate.id === "freeflow.sessionMode");
1378
- const session = await openSettings({
1379
- title: "Freeflow Mode",
1380
- items: [item],
1381
- initialChoice: item,
1382
- ctx,
1383
- onChange: async (_item, value) => {
1384
- const result = await handleModeCommand(String(value), ctx, pi);
1385
- return { changed: result.changed, reloadRequired: false };
1386
- },
1387
- });
1388
- return { changed: session.changed, reloaded: false, error: session.failed ? "write_failed" : undefined };
1389
- }
1390
1112
  if (["enable", "on", "true", "disable", "off", "false"].includes(action)) {
1391
1113
  if (!ensureSettingsIdle(ctx)) return { changed: false, reloaded: false, error: "busy" };
1392
1114
  const enabled = ["enable", "on", "true"].includes(action);
1393
- const item = freeflowItems(raw, modeState, {
1115
+ const item = freeflowItems(raw, {
1394
1116
  scope: "repository",
1395
1117
  layers,
1396
1118
  cognitiveRouting: state.cognitiveRouting,
1397
1119
  ctx,
1398
- hostInfo: pi?.host,
1120
+ runtimeAvailable: isCognitiveRoutingRuntimeAvailable(pi),
1399
1121
  }).find((candidate) => candidate.id === "freeflow.enabled");
1400
1122
  await updateConfig(ctx.cwd, item, enabled, "repository");
1401
1123
  await afterChange(true);
@@ -1409,7 +1131,7 @@ export async function handleFreeflowCommand(args, ctx, afterChange, pi, cognitiv
1409
1131
  }
1410
1132
  if (action && action !== "settings") {
1411
1133
  ctx.ui.notify(
1412
- "Usage: /freeflow, /freeflow settings [local|repo], /freeflow status, /freeflow mode [conversation|workflow|strict-workflow|reset], /freeflow enable, or /freeflow disable",
1134
+ "Usage: /freeflow, /freeflow settings [local|repo], /freeflow status, /freeflow enable, or /freeflow disable",
1413
1135
  "warning",
1414
1136
  );
1415
1137
  return { changed: false, reloaded: false, error: "invalid_action" };
@@ -1430,13 +1152,13 @@ export async function handleFreeflowCommand(args, ctx, afterChange, pi, cognitiv
1430
1152
  let reconcileCognitiveRouting = settingsScope === "session";
1431
1153
  const items =
1432
1154
  settingsScope === "session"
1433
- ? sessionFreeflowItems(state, modeState, cognitiveRoutingController)
1434
- : freeflowItems(raw, modeState, {
1155
+ ? sessionFreeflowItems(state, cognitiveRoutingController)
1156
+ : freeflowItems(raw, {
1435
1157
  scope: settingsScope,
1436
1158
  layers,
1437
1159
  cognitiveRouting: state.cognitiveRouting,
1438
1160
  ctx,
1439
- hostInfo: pi?.host,
1161
+ runtimeAvailable: isCognitiveRoutingRuntimeAvailable(pi),
1440
1162
  });
1441
1163
  const session = await openSettings({
1442
1164
  title:
@@ -1449,14 +1171,10 @@ export async function handleFreeflowCommand(args, ctx, afterChange, pi, cognitiv
1449
1171
  ctx,
1450
1172
  onChange: async (item, value) => {
1451
1173
  if (!ensureSettingsIdle(ctx)) return { changed: false, reloadRequired: false };
1452
- if (!isPiFlowHost(pi?.host) && item.id.startsWith("freeflow.cognitiveRouting.")) {
1453
- ctx.ui.notify("Cognitive Routing is available only in PiFlow.", "warning");
1174
+ if (!isCognitiveRoutingRuntimeAvailable(pi) && item.id.startsWith("freeflow.cognitiveRouting.")) {
1175
+ ctx.ui.notify("Cognitive Routing is unavailable because this host lacks model-state controls.", "warning");
1454
1176
  return { changed: false, reloadRequired: false };
1455
1177
  }
1456
- if (item.id === "freeflow.sessionMode") {
1457
- const result = await handleModeCommand(String(value), ctx, pi);
1458
- return { changed: result.changed, reloadRequired: false };
1459
- }
1460
1178
  if (item.id === "freeflow.cognitiveRouting.profile") {
1461
1179
  if (!cognitiveRoutingController) {
1462
1180
  ctx.ui.notify("Cognitive Routing is unavailable for this session.", "warning");
@@ -1483,8 +1201,6 @@ export async function handleFreeflowCommand(args, ctx, afterChange, pi, cognitiv
1483
1201
  if (item.configScope === "session") {
1484
1202
  const keyById = {
1485
1203
  "freeflow.enabled": "enabled",
1486
- "freeflow.interactionContract": "interactionContract",
1487
- "freeflow.skills.enabled": "skillsEnabled",
1488
1204
  "freeflow.contextVirtualization": "contextVirtualization",
1489
1205
  "freeflow.conversationHistory": "conversationHistory",
1490
1206
  };