@hassangameryt/freeflow 0.5.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +4 -5
- package/README.md +141 -163
- package/capabilities/cognitive-routing/SKILL.md +387 -0
- package/capabilities/context-virtualization/SKILL.md +103 -0
- package/capabilities/conversation-history/SKILL.md +53 -0
- package/command-surface.json +6 -37
- package/hooks/freeflow-runtime-context.mjs +50 -541
- package/hooks/hooks.json +1 -26
- package/hooks/tests/check-runtime-context-hook.sh +114 -308
- package/package.json +27 -17
- package/pi-extension/dist/cognitive-routing/commands.js +96 -0
- package/pi-extension/dist/cognitive-routing/config.js +232 -0
- package/pi-extension/dist/cognitive-routing/controller.js +1292 -0
- package/pi-extension/dist/cognitive-routing/history.js +451 -0
- package/pi-extension/dist/cognitive-routing/host.js +188 -0
- package/pi-extension/dist/cognitive-routing/pi-routing-session.js +414 -0
- package/pi-extension/dist/cognitive-routing/pi-session-control.js +320 -0
- package/pi-extension/dist/cognitive-routing/runtime.js +43 -0
- package/pi-extension/dist/cognitive-routing/tool.js +212 -0
- package/pi-extension/dist/cognitive-routing/types.js +6 -0
- package/pi-extension/dist/context-virtualization/commands.js +89 -0
- package/pi-extension/dist/context-virtualization/projector.js +42 -0
- package/pi-extension/dist/context-virtualization/runtime.js +356 -0
- package/pi-extension/dist/context-virtualization/state.js +57 -0
- package/pi-extension/dist/context-virtualization/types.js +10 -0
- package/pi-extension/dist/conversation-history/passages.js +66 -0
- package/pi-extension/dist/conversation-history/ranking.js +105 -0
- package/pi-extension/dist/conversation-history/runtime.js +226 -0
- package/pi-extension/dist/conversation-history/search.js +56 -0
- package/pi-extension/dist/conversation-history/types.js +1 -0
- package/pi-extension/dist/freeflow-context/resolver.js +120 -0
- package/pi-extension/dist/freeflow-context/runtime.js +80 -0
- package/pi-extension/dist/freeflow-context/source-projector.js +95 -0
- package/pi-extension/dist/freeflow-context/tool.js +308 -0
- package/pi-extension/dist/freeflow-context/types.js +12 -0
- package/pi-extension/dist/freeflow-context/visibility.js +28 -0
- package/pi-extension/dist/index.js +564 -129
- package/pi-extension/dist/runtime/runtime-context.js +357 -470
- package/pi-extension/dist/runtime/runtime-identity.js +5 -0
- package/pi-extension/dist/settings/settings-tui.js +78 -0
- package/pi-extension/dist/settings/settings-ui.js +572 -826
- package/pi-extension/dist/ui/text-component.js +57 -0
- package/pi-extension/src/cognitive-routing/commands.ts +129 -0
- package/pi-extension/src/cognitive-routing/config.ts +303 -0
- package/pi-extension/src/cognitive-routing/controller.ts +1628 -0
- package/pi-extension/src/cognitive-routing/history.ts +650 -0
- package/pi-extension/src/cognitive-routing/host.ts +266 -0
- package/pi-extension/src/cognitive-routing/pi-routing-session.ts +538 -0
- package/pi-extension/src/cognitive-routing/pi-session-control.ts +444 -0
- package/pi-extension/src/cognitive-routing/runtime.ts +57 -0
- package/pi-extension/src/cognitive-routing/tool.ts +273 -0
- package/pi-extension/src/cognitive-routing/types.ts +89 -0
- package/pi-extension/src/context-virtualization/commands.ts +111 -0
- package/pi-extension/src/context-virtualization/projector.ts +62 -0
- package/pi-extension/src/context-virtualization/runtime.ts +406 -0
- package/pi-extension/src/context-virtualization/state.ts +79 -0
- package/pi-extension/src/context-virtualization/types.ts +92 -0
- package/pi-extension/src/conversation-history/passages.ts +81 -0
- package/pi-extension/src/conversation-history/ranking.ts +155 -0
- package/pi-extension/src/conversation-history/runtime.ts +250 -0
- package/pi-extension/src/conversation-history/search.ts +79 -0
- package/pi-extension/src/conversation-history/types.ts +31 -0
- package/pi-extension/src/freeflow-context/resolver.ts +139 -0
- package/pi-extension/src/freeflow-context/runtime.ts +100 -0
- package/pi-extension/src/freeflow-context/source-projector.ts +106 -0
- package/pi-extension/src/freeflow-context/tool.ts +360 -0
- package/pi-extension/src/freeflow-context/types.ts +70 -0
- package/pi-extension/src/freeflow-context/visibility.ts +53 -0
- package/pi-extension/src/index.ts +597 -135
- package/pi-extension/src/runtime/runtime-context.ts +373 -491
- package/pi-extension/src/runtime/runtime-identity.ts +8 -0
- package/pi-extension/src/settings/settings-tui.ts +93 -0
- package/pi-extension/src/settings/settings-ui.ts +679 -910
- package/pi-extension/src/ui/text-component.ts +66 -0
- package/pi-extension/tests/cognitive-routing/commands.test.js +134 -0
- package/pi-extension/tests/cognitive-routing/controller.test.js +1128 -0
- package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +1142 -0
- package/pi-extension/tests/cognitive-routing/history.test.js +274 -0
- package/pi-extension/tests/cognitive-routing/host-fixture.js +4 -0
- package/pi-extension/tests/cognitive-routing/host-identity.test.js +63 -0
- package/pi-extension/tests/cognitive-routing/pi-normal-lifecycle.test.js +434 -0
- package/pi-extension/tests/cognitive-routing/pi-session-control.test.js +174 -0
- package/pi-extension/tests/cognitive-routing/pi-session-history.test.js +91 -0
- package/pi-extension/tests/cognitive-routing/profile-resolution.test.js +279 -0
- package/pi-extension/tests/cognitive-routing/tool.test.js +230 -0
- package/pi-extension/tests/context-virtualization/extension.test.js +749 -0
- package/pi-extension/tests/context-virtualization/projector.test.js +110 -0
- package/pi-extension/tests/context-virtualization/runtime.test.js +216 -0
- package/pi-extension/tests/conversation-history/runtime.test.js +98 -0
- package/pi-extension/tests/conversation-history/search.test.js +97 -0
- package/pi-extension/tests/integration/mode-free-core.test.js +218 -0
- package/pi-extension/tests/integration/pi-extension.test.js +532 -3701
- package/pi-extension/tests/integration/prompt-architecture.test.js +350 -0
- package/pi-extension/tests/integration/unaffected-regressions.test.js +411 -0
- package/runtime/prompts/cognitive-routing.md +10 -0
- package/runtime/prompts/context-virtualization.md +3 -0
- package/runtime/prompts/conversation-history.md +3 -0
- package/runtime/prompts/core.md +84 -0
- package/runtime/prompts/interaction-contract.md +11 -0
- package/skills/action-selection/SKILL.md +140 -0
- package/skills/action-selection/references/trajectory-stalls.md +71 -0
- package/skills/bypass/SKILL.md +109 -38
- package/skills/commit-work/SKILL.md +94 -55
- package/skills/commit-work/references/git-state-edges.md +94 -0
- package/skills/commit-work/references/simple-push.md +92 -0
- package/skills/commit-work/references/staging-decisions.md +79 -46
- package/skills/decision-gate/SKILL.md +80 -22
- package/skills/design-for-depth/SKILL.md +206 -60
- package/skills/design-for-depth/references/design-pressure-signals.md +108 -240
- package/skills/design-for-depth/references/interface-design-loop.md +77 -97
- package/skills/design-for-depth/references/module-and-dependency-design.md +147 -0
- package/skills/design-for-depth/references/software-design-philosophy.md +128 -174
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +136 -0
- package/skills/diagnose-failure/SKILL.md +200 -48
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +18 -6
- package/skills/diagnose-failure/references/{flaky-and-performance.md → flaky-and-performance-diagnosis.md} +13 -5
- package/skills/discuss/SKILL.md +119 -65
- package/skills/discuss/references/discussion-continuity.md +123 -0
- package/skills/evaluate-skill/SKILL.md +166 -52
- package/skills/evaluate-skill/references/{definition-schema.md → evaluation-definition-schema.md} +43 -3
- package/skills/evaluate-skill/references/evaluation-design.md +56 -30
- package/skills/evaluate-skill/references/execution-and-evidence.md +8 -3
- package/skills/evaluate-skill/references/review-and-revision.md +62 -21
- package/skills/evaluate-skill/scripts/lib/definitions.mjs +114 -3
- package/skills/evaluate-skill/scripts/lib/grade-interaction.mjs +156 -1
- package/skills/evaluate-skill/scripts/lib/grade.mjs +9 -1
- package/skills/evaluate-skill/scripts/lib/pi.mjs +147 -32
- package/skills/evaluate-skill/scripts/lib/rpc.mjs +4 -4
- package/skills/evaluate-skill/scripts/lib/runner.mjs +36 -14
- package/skills/evaluate-skill/scripts/lib/sandbox.mjs +92 -0
- package/skills/evaluate-skill/scripts/pi-guard.mjs +1 -1
- package/skills/evaluate-skill/scripts/pi-observer.mjs +66 -0
- package/skills/evaluate-skill/scripts/skill-eval.mjs +6 -5
- package/skills/execute-work/SKILL.md +99 -57
- package/skills/execute-work/references/code-practices.md +4 -4
- package/skills/execute-work/references/execute-work-edges.md +62 -0
- package/skills/finish-branch/SKILL.md +2 -2
- package/skills/finish-branch/references/integration-options.md +1 -1
- package/skills/handoff/SKILL.md +3 -3
- package/skills/launch-work/SKILL.md +1 -1
- package/skills/launch-work/references/launch-readiness.md +2 -2
- package/skills/migration-work/SKILL.md +2 -2
- package/skills/migration-work/references/migration-lifecycle.md +1 -1
- package/skills/release-work/SKILL.md +1 -1
- package/skills/release-work/references/release-evidence.md +1 -1
- package/skills/review-artifact/SKILL.md +129 -66
- package/skills/review-artifact/references/adjudicate-artifact-review.md +101 -0
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +159 -0
- package/skills/review-work/SKILL.md +113 -68
- package/skills/review-work/references/adjudicate-work-review.md +97 -0
- package/skills/review-work/references/independent-work-reviewer-contract.md +139 -0
- package/skills/review-work/references/security-risk-lens.md +18 -16
- package/skills/setup-freeflow/SKILL.md +16 -17
- package/skills/setup-freeflow/references/activation-contract.md +24 -30
- package/skills/setup-freeflow/references/host-setup.md +6 -7
- package/skills/simplify-code/SKILL.md +97 -39
- package/skills/simplify-code/references/simplification-patterns.md +1 -1
- package/skills/tdd/SKILL.md +100 -53
- package/skills/tdd/references/test-design.md +3 -3
- package/skills/track-work/SKILL.md +195 -58
- package/skills/track-work/references/working-record-format.md +515 -0
- package/skills/track-work/scripts/lib/document.mjs +713 -0
- package/skills/track-work/scripts/lib/format.mjs +166 -0
- package/skills/track-work/scripts/lib/store.mjs +233 -0
- package/skills/track-work/scripts/lib/transitions.mjs +790 -0
- package/skills/track-work/scripts/lib/views.mjs +40 -0
- package/skills/track-work/scripts/working-record.mjs +316 -0
- package/skills/verify-work/SKILL.md +57 -19
- package/skills/verify-work/references/browser-runtime-evidence.md +2 -2
- package/skills/verify-work/references/integration-evidence.md +1 -7
- package/skills/verify-work/references/performance-evidence.md +2 -2
- package/skills/workflow/SKILL.md +137 -55
- package/skills/workflow/references/domain-skill-composition.md +26 -40
- package/skills/write-plan/SKILL.md +1 -1
- package/skills/write-skill/SKILL.md +218 -61
- package/skills/write-skill/references/activation-boundaries.md +63 -21
- package/skills/write-skill/references/agent-first-instructions.md +61 -27
- package/skills/write-skill/references/progressive-disclosure.md +97 -33
- package/skills/write-skill/references/skill-dependency-graphs.md +190 -0
- package/capabilities/output-router/SKILL.md +0 -206
- package/capabilities/output-router/references/safety-policy.md +0 -40
- package/capabilities/output-router/references/setup.md +0 -110
- package/pi-extension/dist/output-router/host-producer-identification.js +0 -232
- package/pi-extension/dist/output-router/native-safety-net.js +0 -216
- package/pi-extension/dist/output-router/observed-tool-routing.js +0 -122
- package/pi-extension/dist/output-router/renderers.js +0 -1023
- package/pi-extension/dist/output-router/router-tools.js +0 -554
- package/pi-extension/dist/output-router/schemas.js +0 -383
- package/pi-extension/dist/output-router/status.js +0 -744
- package/pi-extension/dist/output-router/utils.js +0 -502
- package/pi-extension/src/output-router/host-producer-identification.ts +0 -256
- package/pi-extension/src/output-router/native-safety-net.ts +0 -248
- package/pi-extension/src/output-router/observed-tool-routing.ts +0 -134
- package/pi-extension/src/output-router/renderers.ts +0 -1108
- package/pi-extension/src/output-router/router-tools.ts +0 -579
- package/pi-extension/src/output-router/schemas.ts +0 -387
- package/pi-extension/src/output-router/status.ts +0 -791
- package/pi-extension/src/output-router/utils.ts +0 -554
- package/pi-extension/tests/output-router/observed-producers.test.js +0 -132
- package/pi-extension/tests/output-router/search.test.js +0 -722
- package/router/dist/benchmarks/benchmark-harness.d.ts +0 -35
- package/router/dist/benchmarks/benchmark-harness.js +0 -92
- package/router/dist/benchmarks/benchmarks.d.ts +0 -109
- package/router/dist/benchmarks/benchmarks.js +0 -979
- package/router/dist/benchmarks/codex-qa-benchmarks.d.ts +0 -95
- package/router/dist/benchmarks/codex-qa-benchmarks.js +0 -500
- package/router/dist/benchmarks/command-benchmarks.d.ts +0 -143
- package/router/dist/benchmarks/command-benchmarks.js +0 -698
- package/router/dist/benchmarks/context-mode-normalized-benchmarks.d.ts +0 -82
- package/router/dist/benchmarks/context-mode-normalized-benchmarks.js +0 -773
- package/router/dist/benchmarks/context-mode-real-deep-benchmark.d.ts +0 -132
- package/router/dist/benchmarks/context-mode-real-deep-benchmark.js +0 -1380
- package/router/dist/benchmarks/context-saving-baseline.d.ts +0 -60
- package/router/dist/benchmarks/context-saving-baseline.js +0 -470
- package/router/dist/benchmarks/index-benchmarks.d.ts +0 -103
- package/router/dist/benchmarks/index-benchmarks.js +0 -862
- package/router/dist/benchmarks/storage-policy-benchmarks.d.ts +0 -101
- package/router/dist/benchmarks/storage-policy-benchmarks.js +0 -618
- package/router/dist/benchmarks/vault-index-benchmarks.d.ts +0 -56
- package/router/dist/benchmarks/vault-index-benchmarks.js +0 -322
- package/router/dist/config/config.d.ts +0 -103
- package/router/dist/config/config.js +0 -632
- package/router/dist/config/router-contract.d.ts +0 -10
- package/router/dist/config/router-contract.js +0 -54
- package/router/dist/config/schema.d.ts +0 -27
- package/router/dist/config/schema.js +0 -648
- package/router/dist/config/types.d.ts +0 -573
- package/router/dist/config/types.js +0 -41
- package/router/dist/evidence/bounded-evidence.d.ts +0 -40
- package/router/dist/evidence/bounded-evidence.js +0 -323
- package/router/dist/evidence/evidence-range-selector.d.ts +0 -24
- package/router/dist/evidence/evidence-range-selector.js +0 -232
- package/router/dist/evidence/evidence-search.d.ts +0 -27
- package/router/dist/evidence/evidence-search.js +0 -490
- package/router/dist/evidence/evidence.d.ts +0 -38
- package/router/dist/evidence/evidence.js +0 -200
- package/router/dist/evidence/failure-contracts.d.ts +0 -37
- package/router/dist/evidence/failure-contracts.js +0 -166
- package/router/dist/evidence/line-ranges.d.ts +0 -24
- package/router/dist/evidence/line-ranges.js +0 -22
- package/router/dist/experiments/local-index.d.ts +0 -64
- package/router/dist/experiments/local-index.js +0 -581
- package/router/dist/index.d.ts +0 -30
- package/router/dist/index.js +0 -32
- package/router/dist/local/local-traversal.d.ts +0 -18
- package/router/dist/local/local-traversal.js +0 -334
- package/router/dist/processing/engine.d.ts +0 -132
- package/router/dist/processing/engine.js +0 -533
- package/router/dist/processing/reducers.d.ts +0 -280
- package/router/dist/processing/reducers.js +0 -1673
- package/router/dist/processing/renderers.d.ts +0 -31
- package/router/dist/processing/renderers.js +0 -195
- package/router/dist/processing/scripts.d.ts +0 -91
- package/router/dist/processing/scripts.js +0 -386
- package/router/dist/repo/repo-traversal.d.ts +0 -18
- package/router/dist/repo/repo-traversal.js +0 -245
- package/router/dist/routing/observed-reducers.d.ts +0 -41
- package/router/dist/routing/observed-reducers.js +0 -661
- package/router/dist/routing/observed-routing.d.ts +0 -26
- package/router/dist/routing/observed-routing.js +0 -378
- package/router/dist/routing/parsers.d.ts +0 -16
- package/router/dist/routing/parsers.js +0 -521
- package/router/dist/routing/run-filters.d.ts +0 -60
- package/router/dist/routing/run-filters.js +0 -238
- package/router/dist/routing/run-reducers.d.ts +0 -49
- package/router/dist/routing/run-reducers.js +0 -122
- package/router/dist/sandbox/adapter-roots.d.ts +0 -46
- package/router/dist/sandbox/adapter-roots.js +0 -66
- package/router/dist/sandbox/eryx-python-adapter.d.ts +0 -13
- package/router/dist/sandbox/eryx-python-adapter.js +0 -868
- package/router/dist/sandbox/jq-wasm-adapter.d.ts +0 -9
- package/router/dist/sandbox/jq-wasm-adapter.js +0 -429
- package/router/dist/sandbox/quickjs-wasi-adapter.d.ts +0 -13
- package/router/dist/sandbox/quickjs-wasi-adapter.js +0 -384
- package/router/dist/sandbox/script-sandbox.d.ts +0 -134
- package/router/dist/sandbox/script-sandbox.js +0 -337
- package/router/dist/setup/script-transform-adapters.d.ts +0 -32
- package/router/dist/setup/script-transform-adapters.js +0 -278
- package/router/dist/tools/batch.d.ts +0 -33
- package/router/dist/tools/batch.js +0 -586
- package/router/dist/tools/run.d.ts +0 -62
- package/router/dist/tools/run.js +0 -1304
- package/router/dist/tools/search.d.ts +0 -66
- package/router/dist/tools/search.js +0 -1364
- package/router/dist/transform/engine.d.ts +0 -168
- package/router/dist/transform/engine.js +0 -2072
- package/router/dist/vault/vault-index.d.ts +0 -125
- package/router/dist/vault/vault-index.js +0 -416
- package/router/dist/vault/vault.d.ts +0 -138
- package/router/dist/vault/vault.js +0 -630
- package/runtime/interaction-contract.md +0 -16
- package/skills/discuss/references/checkpoints.md +0 -66
- package/skills/execute-work/references/execution-loop.md +0 -77
- package/skills/mode-contract/SKILL.md +0 -104
- package/skills/review-artifact/references/reviewer-prompt.md +0 -148
- package/skills/review-work/references/reviewer-prompt.md +0 -134
- package/skills/track-work/references/working-record-schema.md +0 -378
- package/skills/workflow/references/workflow-loop.md +0 -92
- /package/skills/handoff/references/{templates.md → handoff-templates.md} +0 -0
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
|
|
5
|
+
import { supportsCognitiveRoutingModelRegistry } from "../cognitive-routing/host.js";
|
|
6
6
|
export const WORKFLOW_COMMANDS = [
|
|
7
7
|
{ command: "discuss", skill: "discuss" },
|
|
8
|
-
{ command: "
|
|
8
|
+
{ command: "action-selection", skill: "action-selection" },
|
|
9
9
|
{ command: "track-work", skill: "track-work" },
|
|
10
10
|
{ command: "write-spec", skill: "write-spec" },
|
|
11
11
|
{ command: "review-artifact", skill: "review-artifact" },
|
|
12
12
|
{ command: "write-plan", skill: "write-plan" },
|
|
13
13
|
{ command: "execute-work", skill: "execute-work" },
|
|
14
|
-
{ command: "execute-plan", skill: "execute-work" },
|
|
15
14
|
{ command: "simplify-code", skill: "simplify-code" },
|
|
16
15
|
{ command: "migration-work", skill: "migration-work" },
|
|
17
16
|
{ command: "diagnose-failure", skill: "diagnose-failure" },
|
|
@@ -26,6 +25,7 @@ export const WORKFLOW_COMMANDS = [
|
|
|
26
25
|
];
|
|
27
26
|
export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-skill"];
|
|
28
27
|
export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
28
|
+
"action-selection",
|
|
29
29
|
"bypass",
|
|
30
30
|
"commit-work",
|
|
31
31
|
"decision-gate",
|
|
@@ -37,7 +37,6 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
37
37
|
"execute-work",
|
|
38
38
|
"finish-branch",
|
|
39
39
|
"handoff",
|
|
40
|
-
"mode-contract",
|
|
41
40
|
"release-work",
|
|
42
41
|
"review-artifact",
|
|
43
42
|
"review-work",
|
|
@@ -52,54 +51,99 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
52
51
|
"write-skill",
|
|
53
52
|
"write-spec",
|
|
54
53
|
];
|
|
54
|
+
export const FREEFLOW_CAPABILITY_SKILL_NAMES = ["cognitive-routing", "context-virtualization", "conversation-history"];
|
|
55
55
|
export function freeflowSkillPath(skillName) {
|
|
56
56
|
return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
|
|
57
57
|
}
|
|
58
|
-
export function
|
|
59
|
-
return
|
|
58
|
+
export function freeflowCapabilitySkillPath(skillName) {
|
|
59
|
+
return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
|
|
60
|
+
}
|
|
61
|
+
export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
62
|
+
const paths = FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
|
|
63
|
+
const capabilityStates = {
|
|
64
|
+
"cognitive-routing": capabilityState?.cognitiveRouting,
|
|
65
|
+
"context-virtualization": capabilityState?.contextVirtualization,
|
|
66
|
+
"conversation-history": capabilityState?.conversationHistory,
|
|
67
|
+
};
|
|
68
|
+
for (const skillName of FREEFLOW_CAPABILITY_SKILL_NAMES) {
|
|
69
|
+
if (capabilityStates[skillName]?.effective === true) {
|
|
70
|
+
paths.push(freeflowCapabilitySkillPath(skillName));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return paths;
|
|
60
74
|
}
|
|
61
|
-
const MODE_STATE_ENTRY = "freeflow-mode";
|
|
62
75
|
const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
|
|
63
|
-
const SESSION_CORE_KEYS = new Set(["enabled", "
|
|
64
|
-
const
|
|
65
|
-
export const
|
|
66
|
-
export const
|
|
76
|
+
const SESSION_CORE_KEYS = new Set(["enabled", "contextVirtualization", "conversationHistory"]);
|
|
77
|
+
export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
|
|
78
|
+
export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
|
|
79
|
+
export const COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-cognitive-routing-runtime-state";
|
|
67
80
|
export const WORKFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-workflow-bootstrap";
|
|
81
|
+
export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-routing-bootstrap";
|
|
82
|
+
export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
|
|
68
83
|
let runtimeContextCache = null;
|
|
69
|
-
let currentModeOverride = null;
|
|
70
84
|
let currentSessionOverrides = {};
|
|
71
|
-
|
|
85
|
+
export function isPromptAvailable(value) {
|
|
86
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
87
|
+
}
|
|
88
|
+
export function hasUsableMandatoryPrompts(freeflowContext) {
|
|
89
|
+
return (
|
|
90
|
+
isPromptAvailable(freeflowContext?.corePrompt) && isPromptAvailable(freeflowContext?.interactionContractPrompt)
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
async function readPromptFile(url) {
|
|
94
|
+
try {
|
|
95
|
+
const prompt = await readFile(url, "utf8");
|
|
96
|
+
return isPromptAvailable(prompt) ? prompt.trim() : null;
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
72
101
|
async function loadRuntimeContext(capabilityState = undefined) {
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
102
|
+
const freeflowEnabled = capabilityState?.enabled === true;
|
|
103
|
+
const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
|
|
104
|
+
const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
|
|
105
|
+
const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
|
|
106
|
+
const [
|
|
107
|
+
corePrompt,
|
|
108
|
+
interactionContractPrompt,
|
|
109
|
+
cognitiveRoutingPrompt,
|
|
110
|
+
contextVirtualizationPrompt,
|
|
111
|
+
conversationHistoryPrompt,
|
|
112
|
+
] = await Promise.all([
|
|
113
|
+
freeflowEnabled
|
|
114
|
+
? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
|
|
115
|
+
: Promise.resolve(null),
|
|
116
|
+
freeflowEnabled
|
|
117
|
+
? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
|
|
118
|
+
: Promise.resolve(null),
|
|
119
|
+
cognitiveRoutingEnabled
|
|
120
|
+
? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
|
|
79
121
|
: Promise.resolve(null),
|
|
80
|
-
|
|
81
|
-
?
|
|
122
|
+
contextVirtualizationEnabled
|
|
123
|
+
? readPromptFile(new URL("../../../runtime/prompts/context-virtualization.md", import.meta.url))
|
|
82
124
|
: Promise.resolve(null),
|
|
83
|
-
|
|
84
|
-
?
|
|
125
|
+
conversationHistoryEnabled
|
|
126
|
+
? readPromptFile(new URL("../../../runtime/prompts/conversation-history.md", import.meta.url))
|
|
85
127
|
: Promise.resolve(null),
|
|
86
128
|
]);
|
|
87
|
-
return {
|
|
129
|
+
return {
|
|
130
|
+
corePrompt,
|
|
131
|
+
interactionContractPrompt,
|
|
132
|
+
cognitiveRoutingPrompt,
|
|
133
|
+
contextVirtualizationPrompt,
|
|
134
|
+
conversationHistoryPrompt,
|
|
135
|
+
};
|
|
88
136
|
}
|
|
89
137
|
function runtimeContextCacheSatisfies(capabilityState) {
|
|
90
|
-
if (!runtimeContextCache)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (capabilityState?.outputRouter?.enabled === true && !runtimeContextCache.outputRouterSkill) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
return true;
|
|
138
|
+
if (!runtimeContextCache) return false;
|
|
139
|
+
const expected = {
|
|
140
|
+
corePrompt: capabilityState?.enabled === true,
|
|
141
|
+
interactionContractPrompt: capabilityState?.enabled === true,
|
|
142
|
+
cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
|
|
143
|
+
contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
|
|
144
|
+
conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
|
|
145
|
+
};
|
|
146
|
+
return Object.entries(expected).every(([key, required]) => !required || isPromptAvailable(runtimeContextCache[key]));
|
|
103
147
|
}
|
|
104
148
|
export async function refreshRuntimeContext(capabilityState = undefined) {
|
|
105
149
|
runtimeContextCache = await loadRuntimeContext(capabilityState);
|
|
@@ -111,67 +155,45 @@ export async function getRuntimeContext(capabilityState = undefined) {
|
|
|
111
155
|
}
|
|
112
156
|
return refreshRuntimeContext(capabilityState);
|
|
113
157
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
158
|
+
const BOOTSTRAP_COMPONENTS = Object.freeze({
|
|
159
|
+
workflow: "workflow",
|
|
160
|
+
cognitiveRouting: "cognitive-routing",
|
|
161
|
+
});
|
|
162
|
+
function bootstrapEntryComponents(entry) {
|
|
163
|
+
const isCustomMessage = entry?.role === "custom" || entry?.type === "custom_message" || entry?.type === "custom";
|
|
164
|
+
if (!isCustomMessage) return [];
|
|
165
|
+
if (entry.customType === FREEFLOW_BOOTSTRAP_MESSAGE_TYPE) {
|
|
166
|
+
if (Array.isArray(entry.details?.components)) return entry.details.components;
|
|
167
|
+
return [
|
|
168
|
+
...(entry.content?.includes("<!-- freeflow-bootstrap:workflow -->") ? [BOOTSTRAP_COMPONENTS.workflow] : []),
|
|
169
|
+
...(entry.content?.includes("<!-- freeflow-bootstrap:cognitive-routing -->")
|
|
170
|
+
? [BOOTSTRAP_COMPONENTS.cognitiveRouting]
|
|
171
|
+
: []),
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
if (entry.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE) {
|
|
175
|
+
return [BOOTSTRAP_COMPONENTS.workflow];
|
|
176
|
+
}
|
|
177
|
+
if (entry.customType === COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE) {
|
|
178
|
+
return [BOOTSTRAP_COMPONENTS.cognitiveRouting];
|
|
130
179
|
}
|
|
131
180
|
return [];
|
|
132
181
|
}
|
|
133
|
-
export function
|
|
134
|
-
|
|
135
|
-
return undefined;
|
|
136
|
-
}
|
|
137
|
-
const alreadyLoaded = activeSessionEntries(sessionManager).some(
|
|
138
|
-
(entry) => entry?.type === "custom_message" && entry?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
|
|
139
|
-
);
|
|
140
|
-
if (alreadyLoaded) {
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
return {
|
|
144
|
-
customType: WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
|
|
145
|
-
content: `# Freeflow Workflow Bootstrap\n\n${freeflowContext.workflowSkill.trim()}`,
|
|
146
|
-
display: false,
|
|
147
|
-
details: { skill: "workflow", source: "first-turn-bootstrap" },
|
|
148
|
-
};
|
|
182
|
+
export function filterBootstrapMessage(message) {
|
|
183
|
+
return bootstrapEntryComponents(message).length === 0 ? message : undefined;
|
|
149
184
|
}
|
|
150
185
|
function isRecord(value) {
|
|
151
186
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
152
187
|
}
|
|
153
188
|
function validateCoreConfigFields(value) {
|
|
154
|
-
if (value.defaultMode !== undefined && !VALID_MODES.has(value.defaultMode)) {
|
|
155
|
-
return `invalid defaultMode: ${JSON.stringify(value.defaultMode)}`;
|
|
156
|
-
}
|
|
157
189
|
if (value.enabled !== undefined && typeof value.enabled !== "boolean") {
|
|
158
190
|
return "enabled must be a boolean";
|
|
159
191
|
}
|
|
160
|
-
if (value.
|
|
161
|
-
return "
|
|
192
|
+
if (value.contextVirtualization !== undefined && typeof value.contextVirtualization !== "boolean") {
|
|
193
|
+
return "contextVirtualization must be a boolean";
|
|
162
194
|
}
|
|
163
|
-
if (value.
|
|
164
|
-
|
|
165
|
-
return "skills must be an object";
|
|
166
|
-
}
|
|
167
|
-
for (const key of Object.keys(value.skills)) {
|
|
168
|
-
if (key !== "enabled") {
|
|
169
|
-
return `unsupported skills config key: ${key}`;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (value.skills.enabled !== undefined && typeof value.skills.enabled !== "boolean") {
|
|
173
|
-
return "skills.enabled must be a boolean";
|
|
174
|
-
}
|
|
195
|
+
if (value.conversationHistory !== undefined && typeof value.conversationHistory !== "boolean") {
|
|
196
|
+
return "conversationHistory must be a boolean";
|
|
175
197
|
}
|
|
176
198
|
return null;
|
|
177
199
|
}
|
|
@@ -179,14 +201,15 @@ function validateFreeflowConfigShape(value) {
|
|
|
179
201
|
if (!isRecord(value)) {
|
|
180
202
|
return "config must be a JSON object";
|
|
181
203
|
}
|
|
204
|
+
// Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
|
|
182
205
|
const allowedKeys = new Set([
|
|
183
206
|
"enabled",
|
|
184
|
-
"defaultMode",
|
|
185
|
-
"interactionContract",
|
|
186
|
-
"skills",
|
|
187
207
|
"outputRouter",
|
|
188
208
|
"observedRouting",
|
|
189
209
|
"scriptTransform",
|
|
210
|
+
"cognitiveRouting",
|
|
211
|
+
"contextVirtualization",
|
|
212
|
+
"conversationHistory",
|
|
190
213
|
]);
|
|
191
214
|
for (const key of Object.keys(value)) {
|
|
192
215
|
if (!allowedKeys.has(key)) {
|
|
@@ -206,7 +229,13 @@ function validateFreeflowLocalConfigShape(value) {
|
|
|
206
229
|
if (!isRecord(value)) {
|
|
207
230
|
return "local config must be a JSON object";
|
|
208
231
|
}
|
|
209
|
-
const allowedKeys = new Set([
|
|
232
|
+
const allowedKeys = new Set([
|
|
233
|
+
"enabled",
|
|
234
|
+
"processing",
|
|
235
|
+
"cognitiveRouting",
|
|
236
|
+
"contextVirtualization",
|
|
237
|
+
"conversationHistory",
|
|
238
|
+
]);
|
|
210
239
|
for (const key of Object.keys(value)) {
|
|
211
240
|
if (!allowedKeys.has(key)) {
|
|
212
241
|
return `unsupported top-level local config key: ${key}`;
|
|
@@ -275,23 +304,18 @@ function resolveLayeredValue(repository, local, key, fallback) {
|
|
|
275
304
|
}
|
|
276
305
|
function resolveCoreConfig(repository, local) {
|
|
277
306
|
const enabled = resolveLayeredValue(repository, local, "enabled", true);
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
|
|
281
|
-
const localSkills = isRecord(local.skills) ? local.skills : {};
|
|
282
|
-
const skillsEnabled = resolveLayeredValue(repositorySkills, localSkills, "enabled", true);
|
|
307
|
+
const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
|
|
308
|
+
const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
|
|
283
309
|
return {
|
|
284
310
|
config: {
|
|
285
311
|
enabled: enabled.value,
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
defaultMode: defaultMode.value,
|
|
312
|
+
contextVirtualization: contextVirtualization.value,
|
|
313
|
+
conversationHistory: conversationHistory.value,
|
|
289
314
|
},
|
|
290
315
|
sources: {
|
|
291
316
|
enabled: enabled.source,
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
defaultMode: defaultMode.source,
|
|
317
|
+
contextVirtualization: contextVirtualization.source,
|
|
318
|
+
conversationHistory: conversationHistory.source,
|
|
295
319
|
},
|
|
296
320
|
};
|
|
297
321
|
}
|
|
@@ -309,21 +333,20 @@ function resolveSessionCoreConfig(layers) {
|
|
|
309
333
|
const configured = layers.coreConfig;
|
|
310
334
|
const sources = layers.sources;
|
|
311
335
|
const enabled = currentSessionOverrides.enabled;
|
|
312
|
-
const
|
|
313
|
-
const
|
|
336
|
+
const contextVirtualization = currentSessionOverrides.contextVirtualization;
|
|
337
|
+
const conversationHistory = currentSessionOverrides.conversationHistory;
|
|
314
338
|
return {
|
|
315
339
|
config: {
|
|
316
340
|
enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
|
|
317
|
-
|
|
318
|
-
typeof
|
|
319
|
-
|
|
320
|
-
|
|
341
|
+
contextVirtualization:
|
|
342
|
+
typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
|
|
343
|
+
conversationHistory:
|
|
344
|
+
typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
|
|
321
345
|
},
|
|
322
346
|
sources: {
|
|
323
347
|
enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
defaultMode: sources.defaultMode,
|
|
348
|
+
contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
|
|
349
|
+
conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
|
|
327
350
|
},
|
|
328
351
|
};
|
|
329
352
|
}
|
|
@@ -351,15 +374,32 @@ export async function readFreeflowConfigLayers(cwd) {
|
|
|
351
374
|
parseError: blockingState?.parseError ?? null,
|
|
352
375
|
};
|
|
353
376
|
}
|
|
354
|
-
export async function readCapabilityState(cwd) {
|
|
377
|
+
export async function readCapabilityState(cwd, host = undefined, extensionHost = undefined) {
|
|
355
378
|
const layers = await readFreeflowConfigLayers(cwd);
|
|
356
|
-
const parsed = layers.repository.valid ? layers.repository.parsed : {};
|
|
357
|
-
const normalized = normalizeFreeflowConfig(parsed);
|
|
358
379
|
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
359
380
|
const enabled = layers.configured && effectiveCore.config.enabled;
|
|
360
|
-
const
|
|
361
|
-
const
|
|
362
|
-
const
|
|
381
|
+
const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
|
|
382
|
+
const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
|
|
383
|
+
const hostSupportsCognitiveRouting = supportsCognitiveRoutingModelRegistry(host);
|
|
384
|
+
const configuredCognitiveRouting = await resolveCognitiveRoutingState(
|
|
385
|
+
layers.repository.parsed,
|
|
386
|
+
layers.local.parsed,
|
|
387
|
+
hostSupportsCognitiveRouting ? host : undefined,
|
|
388
|
+
);
|
|
389
|
+
const disabledReason = enabled ? undefined : { code: "disabled", message: "Freeflow is disabled" };
|
|
390
|
+
const childCapability = (configuredEnabled) => ({
|
|
391
|
+
enabled: configuredEnabled,
|
|
392
|
+
effective: enabled && configuredEnabled,
|
|
393
|
+
...(disabledReason ? { blockingReason: disabledReason } : {}),
|
|
394
|
+
});
|
|
395
|
+
const cognitiveRouting = enabled
|
|
396
|
+
? configuredCognitiveRouting
|
|
397
|
+
: {
|
|
398
|
+
...configuredCognitiveRouting,
|
|
399
|
+
enabled: false,
|
|
400
|
+
effective: false,
|
|
401
|
+
blockingReason: disabledReason,
|
|
402
|
+
};
|
|
363
403
|
return {
|
|
364
404
|
configured: layers.configured,
|
|
365
405
|
repositoryConfigured: layers.repositoryConfigured,
|
|
@@ -375,111 +415,30 @@ export async function readCapabilityState(cwd) {
|
|
|
375
415
|
configuredSources: layers.sources,
|
|
376
416
|
sessionOverrides: { ...currentSessionOverrides },
|
|
377
417
|
configSources: effectiveCore.sources,
|
|
378
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
379
418
|
enabled,
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
skills: {
|
|
385
|
-
enabled: skillsConfigEnabled,
|
|
386
|
-
effective: enabled && skillsConfigEnabled,
|
|
387
|
-
},
|
|
388
|
-
outputRouter: {
|
|
389
|
-
enabled: enabled && outputRouterConfigEnabled,
|
|
390
|
-
configEnabled: outputRouterConfigEnabled,
|
|
391
|
-
},
|
|
419
|
+
contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
|
|
420
|
+
conversationHistory: childCapability(conversationHistoryConfigEnabled),
|
|
421
|
+
hostSupportsCognitiveRouting,
|
|
422
|
+
cognitiveRouting,
|
|
392
423
|
};
|
|
393
424
|
}
|
|
394
425
|
export const readRuntimeState = readCapabilityState;
|
|
395
|
-
export
|
|
396
|
-
const layers = await readFreeflowConfigLayers(cwd);
|
|
397
|
-
const parsed = layers.repository.valid ? layers.repository.parsed : {};
|
|
398
|
-
const localParsed = layers.local.valid ? layers.local.parsed : {};
|
|
399
|
-
const normalized = normalizeFreeflowConfig(parsed);
|
|
400
|
-
const local = normalizeLocalFreeflowConfig(localParsed);
|
|
401
|
-
const freeflowEnabled = layers.configured && layers.coreConfig.enabled;
|
|
402
|
-
const effectiveConfig = freeflowEnabled
|
|
403
|
-
? normalized.config
|
|
404
|
-
: {
|
|
405
|
-
...normalized.config,
|
|
406
|
-
outputRouter: { ...normalized.config.outputRouter, enabled: false },
|
|
407
|
-
observedRouting: {
|
|
408
|
-
...normalized.config.observedRouting,
|
|
409
|
-
enabled: false,
|
|
410
|
-
},
|
|
411
|
-
scriptTransform: {
|
|
412
|
-
...normalized.config.scriptTransform,
|
|
413
|
-
enabled: false,
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
const configWarnings = [...normalized.warnings];
|
|
417
|
-
if (layers.repository.exists && !layers.repository.valid) {
|
|
418
|
-
configWarnings.unshift(
|
|
419
|
-
`.freeflow/config.json could not be parsed; Freeflow runtime is inactive. ${layers.repository.parseError ?? ""}`.trim(),
|
|
420
|
-
);
|
|
421
|
-
}
|
|
422
|
-
if (layers.local.exists && !layers.local.valid) {
|
|
423
|
-
configWarnings.unshift(
|
|
424
|
-
`.freeflow/local.json could not be parsed; Freeflow runtime is inactive. ${layers.local.parseError ?? ""}`.trim(),
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
return {
|
|
428
|
-
config: effectiveConfig.outputRouter,
|
|
429
|
-
freeflowConfig: effectiveConfig,
|
|
430
|
-
localConfig: local.config,
|
|
431
|
-
warnings: [...configWarnings, ...local.warnings],
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
export function notifyRouterConfigWarnings(ctx, routerConfigResult) {
|
|
435
|
-
if (!routerConfigResult.warnings.length) {
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
const key = routerConfigResult.warnings.join("\n");
|
|
439
|
-
if (key === lastRouterConfigWarningKey) {
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
lastRouterConfigWarningKey = key;
|
|
443
|
-
ctx.ui.notify(`Freeflow config warning: ${routerConfigResult.warnings.join(" ")}`, "warning");
|
|
444
|
-
}
|
|
445
|
-
export function restoreModeOverride(ctx) {
|
|
446
|
-
currentModeOverride = null;
|
|
426
|
+
export function restoreSessionOverrides(ctx) {
|
|
447
427
|
currentSessionOverrides = {};
|
|
448
428
|
const entries = ctx.sessionManager?.getBranch?.() ?? ctx.sessionManager?.getEntries?.() ?? [];
|
|
449
429
|
for (const entry of entries) {
|
|
450
|
-
if (entry.type
|
|
451
|
-
if (entry.customType === MODE_STATE_ENTRY) {
|
|
452
|
-
const mode = entry.data?.currentMode;
|
|
453
|
-
currentModeOverride = VALID_MODES.has(mode) ? mode : null;
|
|
454
|
-
} else if (entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
430
|
+
if (entry.type === "custom" && entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
455
431
|
currentSessionOverrides = normalizeSessionOverrides(entry.data?.overrides);
|
|
456
432
|
}
|
|
457
433
|
}
|
|
458
434
|
}
|
|
459
|
-
export
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const sessionMode = VALID_MODES.has(currentModeOverride) ? currentModeOverride : null;
|
|
467
|
-
const resolvedMode = sessionMode ?? effectiveCore.config.defaultMode;
|
|
468
|
-
const active = layers.configured && effectiveCore.config.enabled && effectiveCore.config.skills.enabled;
|
|
469
|
-
return {
|
|
470
|
-
repositoryDefaultMode,
|
|
471
|
-
repositoryDefaultModeSource: VALID_MODES.has(layers.repository.parsed.defaultMode) ? "repository" : "builtin",
|
|
472
|
-
personalDefaultMode,
|
|
473
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
474
|
-
defaultModeSource: effectiveCore.sources.defaultMode,
|
|
475
|
-
currentMode: sessionMode,
|
|
476
|
-
sessionMode,
|
|
477
|
-
resolvedMode,
|
|
478
|
-
active,
|
|
479
|
-
effectiveMode: active ? resolvedMode : null,
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
export function setModeStatus(ctx, modeState, capabilityState = undefined) {
|
|
435
|
+
export function setFreeflowStatus(
|
|
436
|
+
ctx,
|
|
437
|
+
capabilityState = undefined,
|
|
438
|
+
cognitiveRoutingRuntime = undefined,
|
|
439
|
+
freeflowContext = undefined,
|
|
440
|
+
options = {},
|
|
441
|
+
) {
|
|
483
442
|
if (capabilityState && !capabilityState.configured) {
|
|
484
443
|
ctx.ui.setStatus("freeflow", capabilityState.configExists ? "freeflow: config error" : "freeflow: setup needed");
|
|
485
444
|
return;
|
|
@@ -489,188 +448,200 @@ export function setModeStatus(ctx, modeState, capabilityState = undefined) {
|
|
|
489
448
|
ctx.ui.setStatus("freeflow", `freeflow: off${source}`);
|
|
490
449
|
return;
|
|
491
450
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
} else if (capabilityState?.configSources?.interactionContract === "session") {
|
|
496
|
-
active.push("interaction off (session)");
|
|
497
|
-
}
|
|
498
|
-
if (capabilityState?.skills.effective) {
|
|
499
|
-
active.push(`${modeState.effectiveMode}${modeState.currentMode ? " (session)" : ""}`);
|
|
500
|
-
} else if (capabilityState?.configSources?.skillsEnabled === "session") {
|
|
501
|
-
active.push("skills off (session)");
|
|
451
|
+
if (capabilityState?.enabled === true && !hasUsableMandatoryPrompts(freeflowContext)) {
|
|
452
|
+
ctx.ui.setStatus("freeflow", "freeflow: unavailable");
|
|
453
|
+
return;
|
|
502
454
|
}
|
|
503
|
-
|
|
504
|
-
|
|
455
|
+
const active = [];
|
|
456
|
+
const cognitiveRouting = capabilityState?.cognitiveRouting;
|
|
457
|
+
const cognitiveRoutingInactive =
|
|
458
|
+
cognitiveRouting?.enabled === true && cognitiveRoutingRuntime?.runtimeStatus === "inactive";
|
|
459
|
+
const cognitiveRoutingBlocked =
|
|
460
|
+
cognitiveRouting?.enabled === true &&
|
|
461
|
+
(cognitiveRouting?.blockingReason?.code === "runtime_blocked" ||
|
|
462
|
+
cognitiveRoutingRuntime?.runtimeStatus === "blocked");
|
|
463
|
+
const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
|
|
464
|
+
const startupSelectionSuppressesCognitiveRouting = options.startupSelectionSuppressed === true;
|
|
465
|
+
if (cognitiveRoutingInactive) {
|
|
466
|
+
active.push("cognitive inactive");
|
|
467
|
+
} else if (cognitiveRoutingBlocked) {
|
|
468
|
+
active.push(`cognitive blocked · ${cognitiveRoutingRuntime?.runtimeReason ?? "runtime_blocked"}`);
|
|
469
|
+
} else if (cognitiveRoutingActive) {
|
|
470
|
+
const profile = cognitiveRoutingRuntime.activeProfile;
|
|
471
|
+
const control =
|
|
472
|
+
cognitiveRoutingRuntime.controlMode === "manual-standard" ||
|
|
473
|
+
cognitiveRoutingRuntime.controlMode === "manual-reasoning"
|
|
474
|
+
? "manual hold"
|
|
475
|
+
: "automatic";
|
|
476
|
+
active.push(`${profile} · ${control}`);
|
|
477
|
+
} else if (cognitiveRouting?.enabled === true) {
|
|
478
|
+
if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
|
|
479
|
+
active.push("cognitive blocked · runtime_disabled");
|
|
480
|
+
} else if (
|
|
481
|
+
cognitiveRouting.effective === true &&
|
|
482
|
+
cognitiveRoutingRuntime === undefined &&
|
|
483
|
+
options.cognitiveRoutingStartupPending === true &&
|
|
484
|
+
!startupSelectionSuppressesCognitiveRouting
|
|
485
|
+
) {
|
|
486
|
+
const startupProfile =
|
|
487
|
+
cognitiveRouting.sessionStart?.control === "manual"
|
|
488
|
+
? (cognitiveRouting.sessionStart.profile ?? "reasoning")
|
|
489
|
+
: "reasoning";
|
|
490
|
+
active.push(`${startupProfile} · pending`);
|
|
491
|
+
} else {
|
|
492
|
+
const reason =
|
|
493
|
+
cognitiveRouting.effective === true
|
|
494
|
+
? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
|
|
495
|
+
: (cognitiveRouting.blockingReason?.code ?? "unavailable");
|
|
496
|
+
active.push(`cognitive blocked · ${reason}`);
|
|
497
|
+
}
|
|
505
498
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
function modeSourceLabel(source) {
|
|
509
|
-
if (source === "local") return "personal override";
|
|
510
|
-
if (source === "repository") return "repository default";
|
|
511
|
-
return "built-in default";
|
|
512
|
-
}
|
|
513
|
-
function describeModeState(modeState) {
|
|
514
|
-
const configuredDefault = `configured default ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)})`;
|
|
515
|
-
if (modeState.sessionMode) {
|
|
516
|
-
return `session ${modeState.sessionMode}; ${configuredDefault}`;
|
|
499
|
+
if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
|
|
500
|
+
active.push("context");
|
|
517
501
|
}
|
|
518
|
-
|
|
502
|
+
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "active"}`);
|
|
519
503
|
}
|
|
520
504
|
export function skillPrompt(skill, args) {
|
|
521
505
|
const trimmed = args?.trim();
|
|
522
506
|
return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
|
|
523
507
|
}
|
|
524
|
-
function
|
|
525
|
-
if (
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
const outputRouter = capabilityState.outputRouter.enabled ? "enabled" : "disabled";
|
|
554
|
-
return `## Freeflow Capabilities
|
|
555
|
-
|
|
556
|
-
- Interaction contract: ${interactionContract}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
|
|
557
|
-
- Skills: ${skills}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
|
|
558
|
-
- Output router: ${outputRouter}. Configure with \`/freeflow settings\` or \`/output-router\`; inspect with \`/output-router status\`.
|
|
559
|
-
|
|
560
|
-
Disabled capabilities are named only for status/config awareness. Capability-specific instructions and tools are active only while that capability is enabled.`;
|
|
561
|
-
}
|
|
562
|
-
function hasModelFacingCapability(capabilityState) {
|
|
563
|
-
return (
|
|
564
|
-
capabilityState.interactionContract.effective ||
|
|
565
|
-
capabilityState.skills.effective ||
|
|
566
|
-
capabilityState.outputRouter.enabled
|
|
508
|
+
function publicCognitiveRoutingControl(controlMode) {
|
|
509
|
+
if (controlMode === "automatic") return "automatic";
|
|
510
|
+
if (controlMode === "manual-standard" || controlMode === "manual-reasoning") return "manual";
|
|
511
|
+
return "unavailable";
|
|
512
|
+
}
|
|
513
|
+
function publicCognitiveRoutingProfile(activeProfile, effective) {
|
|
514
|
+
if (effective !== true) return "unavailable";
|
|
515
|
+
return activeProfile === "standard" || activeProfile === "reasoning" ? activeProfile : "unavailable";
|
|
516
|
+
}
|
|
517
|
+
function publicCapabilityStatus(capability) {
|
|
518
|
+
if (capability?.effective === true) return "active";
|
|
519
|
+
if (!capability) return "unavailable";
|
|
520
|
+
const blockingCode = capability.blockingReason?.code;
|
|
521
|
+
if (blockingCode && blockingCode !== "disabled") return "unavailable";
|
|
522
|
+
return "inactive";
|
|
523
|
+
}
|
|
524
|
+
function publicCognitiveRoutingStatus(capability, runtime) {
|
|
525
|
+
if (runtime?.runtimeStatus === "inactive") return "inactive";
|
|
526
|
+
return publicCapabilityStatus(capability);
|
|
527
|
+
}
|
|
528
|
+
export function freeflowRuntimeStateMessage(
|
|
529
|
+
capabilityState,
|
|
530
|
+
cognitiveRoutingRuntime = undefined,
|
|
531
|
+
freeflowContext = undefined,
|
|
532
|
+
) {
|
|
533
|
+
const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
|
|
534
|
+
const profile = publicCognitiveRoutingProfile(
|
|
535
|
+
cognitiveRoutingRuntime?.activeProfile,
|
|
536
|
+
cognitiveRoutingEffective && cognitiveRoutingRuntime?.effective === true,
|
|
567
537
|
);
|
|
538
|
+
const control =
|
|
539
|
+
profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
|
|
540
|
+
const mandatoryPromptAvailable = capabilityState?.enabled !== true || hasUsableMandatoryPrompts(freeflowContext);
|
|
541
|
+
const freeflowStatus = capabilityState?.configured
|
|
542
|
+
? capabilityState.enabled
|
|
543
|
+
? mandatoryPromptAvailable
|
|
544
|
+
? "active"
|
|
545
|
+
: "unavailable"
|
|
546
|
+
: "inactive"
|
|
547
|
+
: capabilityState?.configExists
|
|
548
|
+
? "config error"
|
|
549
|
+
: "setup needed";
|
|
550
|
+
return {
|
|
551
|
+
role: "custom",
|
|
552
|
+
customType: FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE,
|
|
553
|
+
content: [
|
|
554
|
+
"# Freeflow Runtime State",
|
|
555
|
+
"",
|
|
556
|
+
"This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
|
|
557
|
+
"",
|
|
558
|
+
`Freeflow: ${freeflowStatus}`,
|
|
559
|
+
"",
|
|
560
|
+
"Capabilities:",
|
|
561
|
+
`- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
|
|
562
|
+
`- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
|
|
563
|
+
`- Cognitive Routing: ${publicCognitiveRoutingStatus(capabilityState?.cognitiveRouting, cognitiveRoutingRuntime)}`,
|
|
564
|
+
"",
|
|
565
|
+
"Cognitive Routing:",
|
|
566
|
+
`- Control: \`${control}\``,
|
|
567
|
+
`- Profile: \`${profile}\``,
|
|
568
|
+
].join("\n"),
|
|
569
|
+
display: false,
|
|
570
|
+
details: { source: "provider-request-runtime-state" },
|
|
571
|
+
};
|
|
568
572
|
}
|
|
569
|
-
function
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
Repository default mode: \`${modeState.repositoryDefaultMode}\` (${modeState.repositoryDefaultModeSource}).
|
|
621
|
-
Personal default override: \`${modeState.personalDefaultMode ?? "none"}\`.
|
|
622
|
-
Configured default mode: \`${modeState.defaultMode}\` (${modeSourceLabel(modeState.defaultModeSource)}).
|
|
623
|
-
Session mode override: \`${modeState.sessionMode ?? "none"}\`.
|
|
624
|
-
Resolved mode: \`${modeState.resolvedMode}\` (inactive because Skills are disabled).
|
|
625
|
-
Effective Freeflow mode: \`none\`.
|
|
626
|
-
|
|
627
|
-
Freeflow workflow modes are dormant until Skills are enabled with \`/freeflow settings\`.`;
|
|
628
|
-
}
|
|
629
|
-
function controlPlaneContext(modeState, capabilityState) {
|
|
630
|
-
return `# Freeflow Control Plane
|
|
631
|
-
|
|
632
|
-
Freeflow is enabled for this repo, but no model-facing capabilities are enabled.
|
|
633
|
-
These lines are status/config awareness only; do not apply Freeflow workflow or output-router behavior.
|
|
634
|
-
|
|
635
|
-
${inactiveModeContext(modeState)}
|
|
636
|
-
|
|
637
|
-
${capabilityContext(capabilityState)}
|
|
638
|
-
|
|
639
|
-
Use \`/freeflow settings\` to enable the Interaction Contract, Skills, or Output Router. The read-only \`freeflow_status\` diagnostic may be available so the model can answer setup/status questions.`;
|
|
640
|
-
}
|
|
641
|
-
export function runtimeContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
|
|
642
|
-
if (!capabilityState.configured) {
|
|
573
|
+
export function withoutFreeflowRuntimeState(messages) {
|
|
574
|
+
return (Array.isArray(messages) ? messages : []).filter(
|
|
575
|
+
(message) =>
|
|
576
|
+
message?.customType !== FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
|
|
577
|
+
message?.customType !== COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
function lastUserMessageIndex(messages) {
|
|
581
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
582
|
+
if (messages[index]?.role === "user") return index;
|
|
583
|
+
}
|
|
584
|
+
return -1;
|
|
585
|
+
}
|
|
586
|
+
function insertRuntimeStateBeforeLatestUser(messages, runtimeState) {
|
|
587
|
+
const latestUserIndex = lastUserMessageIndex(messages);
|
|
588
|
+
if (latestUserIndex < 0) return [...messages, runtimeState];
|
|
589
|
+
return [...messages.slice(0, latestUserIndex), runtimeState, ...messages.slice(latestUserIndex)];
|
|
590
|
+
}
|
|
591
|
+
export function withFreeflowRuntimeState(
|
|
592
|
+
messages,
|
|
593
|
+
capabilityState,
|
|
594
|
+
cognitiveRoutingRuntime = undefined,
|
|
595
|
+
freeflowContext = undefined,
|
|
596
|
+
options = {},
|
|
597
|
+
) {
|
|
598
|
+
const source = Array.isArray(messages) ? messages : [];
|
|
599
|
+
const runtimeState = freeflowRuntimeStateMessage(capabilityState, cognitiveRoutingRuntime, freeflowContext);
|
|
600
|
+
const runtimeStateMessages = source.filter(
|
|
601
|
+
(message) =>
|
|
602
|
+
message?.customType === FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE ||
|
|
603
|
+
message?.customType === COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
|
|
604
|
+
);
|
|
605
|
+
const withoutRuntimeState = withoutFreeflowRuntimeState(source);
|
|
606
|
+
const expectedRuntimeStateIndex = lastUserMessageIndex(withoutRuntimeState);
|
|
607
|
+
const runtimeStateIndex = source.findIndex((message) => message?.customType === FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE);
|
|
608
|
+
const unchanged =
|
|
609
|
+
options.force !== true &&
|
|
610
|
+
runtimeStateMessages.length === 1 &&
|
|
611
|
+
runtimeStateMessages[0]?.customType === FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
|
|
612
|
+
runtimeStateMessages[0]?.content === runtimeState.content &&
|
|
613
|
+
runtimeStateIndex === (expectedRuntimeStateIndex < 0 ? withoutRuntimeState.length : expectedRuntimeStateIndex);
|
|
614
|
+
if (unchanged) return source;
|
|
615
|
+
return insertRuntimeStateBeforeLatestUser(withoutRuntimeState, runtimeState);
|
|
616
|
+
}
|
|
617
|
+
export function runtimeContext(freeflowContext, capabilityState) {
|
|
618
|
+
if (
|
|
619
|
+
capabilityState?.configured !== true ||
|
|
620
|
+
capabilityState?.enabled !== true ||
|
|
621
|
+
!hasUsableMandatoryPrompts(freeflowContext)
|
|
622
|
+
) {
|
|
643
623
|
return "";
|
|
644
624
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
if (
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
Freeflow Pi extension loaded this before the agent turn.
|
|
666
|
-
Runtime delivery: confirmed for this Pi \`before_agent_start\` invocation.
|
|
667
|
-
These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.
|
|
668
|
-
|
|
669
|
-
${modeText}
|
|
670
|
-
|
|
671
|
-
${capabilityContext(capabilityState)}${interactionContractText}${routerText}
|
|
672
|
-
|
|
673
|
-
This Pi extension loads enabled runtime context before every agent turn and routes commands only; it does not enforce policy, block tools, grant permissions, or create repo-local hooks.`;
|
|
625
|
+
const blocks = [freeflowContext.corePrompt.trim(), freeflowContext.interactionContractPrompt.trim()];
|
|
626
|
+
if (
|
|
627
|
+
capabilityState.cognitiveRouting?.effective === true &&
|
|
628
|
+
isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)
|
|
629
|
+
) {
|
|
630
|
+
blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
|
|
631
|
+
}
|
|
632
|
+
if (
|
|
633
|
+
capabilityState.contextVirtualization?.effective === true &&
|
|
634
|
+
isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
|
|
635
|
+
) {
|
|
636
|
+
blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
|
|
637
|
+
}
|
|
638
|
+
if (
|
|
639
|
+
capabilityState.conversationHistory?.effective === true &&
|
|
640
|
+
isPromptAvailable(freeflowContext.conversationHistoryPrompt)
|
|
641
|
+
) {
|
|
642
|
+
blocks.push(freeflowContext.conversationHistoryPrompt.trim());
|
|
643
|
+
}
|
|
644
|
+
return blocks.filter(Boolean).join("\n\n");
|
|
674
645
|
}
|
|
675
646
|
export async function setSessionCoreOverride(key, value, ctx, pi) {
|
|
676
647
|
if (!SESSION_CORE_KEYS.has(key)) {
|
|
@@ -693,106 +664,22 @@ export async function setSessionCoreOverride(key, value, ctx, pi) {
|
|
|
693
664
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: { ...currentSessionOverrides } });
|
|
694
665
|
return {
|
|
695
666
|
changed: true,
|
|
696
|
-
reloadRequired: key === "enabled"
|
|
667
|
+
reloadRequired: key === "enabled",
|
|
697
668
|
sessionOverrides: { ...currentSessionOverrides },
|
|
698
|
-
capabilityState: await readCapabilityState(ctx.cwd),
|
|
669
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
699
670
|
};
|
|
700
671
|
}
|
|
701
672
|
export async function resetSessionOverrides(ctx, pi) {
|
|
702
673
|
const hadCoreOverrides = Object.keys(currentSessionOverrides).length > 0;
|
|
703
|
-
const reloadRequired =
|
|
704
|
-
Object.hasOwn(currentSessionOverrides, "enabled") || Object.hasOwn(currentSessionOverrides, "skillsEnabled");
|
|
705
|
-
const hadModeOverride = VALID_MODES.has(currentModeOverride);
|
|
674
|
+
const reloadRequired = Object.hasOwn(currentSessionOverrides, "enabled");
|
|
706
675
|
if (hadCoreOverrides) {
|
|
707
676
|
currentSessionOverrides = {};
|
|
708
677
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: {} });
|
|
709
678
|
}
|
|
710
|
-
if (hadModeOverride) {
|
|
711
|
-
await setSessionMode(null, ctx, pi);
|
|
712
|
-
}
|
|
713
679
|
return {
|
|
714
|
-
changed: hadCoreOverrides
|
|
680
|
+
changed: hadCoreOverrides,
|
|
715
681
|
reloadRequired,
|
|
716
682
|
sessionOverrides: { ...currentSessionOverrides },
|
|
717
|
-
|
|
683
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
718
684
|
};
|
|
719
685
|
}
|
|
720
|
-
export async function setSessionMode(mode, ctx, pi) {
|
|
721
|
-
const nextMode = mode === "default" || mode === "reset" || mode === null ? null : mode;
|
|
722
|
-
if (nextMode !== null && !VALID_MODES.has(nextMode)) {
|
|
723
|
-
throw new Error(`Invalid Freeflow mode: ${String(mode)}`);
|
|
724
|
-
}
|
|
725
|
-
currentModeOverride = nextMode;
|
|
726
|
-
pi?.appendEntry?.(MODE_STATE_ENTRY, { currentMode: nextMode });
|
|
727
|
-
return readModeState(ctx.cwd);
|
|
728
|
-
}
|
|
729
|
-
export async function handleModeCommand(args, ctx, pi) {
|
|
730
|
-
const arg = args?.trim();
|
|
731
|
-
const capabilityState = await readCapabilityState(ctx.cwd);
|
|
732
|
-
const inactiveModeState = await readModeState(ctx.cwd);
|
|
733
|
-
if (!capabilityState.configured) {
|
|
734
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
735
|
-
ctx.ui.notify(
|
|
736
|
-
"Freeflow is installed but this repo is not set up. Run /setup-freeflow before changing mode.",
|
|
737
|
-
"warning",
|
|
738
|
-
);
|
|
739
|
-
return { changed: false, error: "not_configured" };
|
|
740
|
-
}
|
|
741
|
-
if (!capabilityState.enabled) {
|
|
742
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
743
|
-
ctx.ui.notify(
|
|
744
|
-
"Freeflow is disabled for this repo. Use /freeflow enable or /freeflow settings to re-enable it.",
|
|
745
|
-
"warning",
|
|
746
|
-
);
|
|
747
|
-
return { changed: false, error: "freeflow_disabled" };
|
|
748
|
-
}
|
|
749
|
-
if (!capabilityState.skills.effective) {
|
|
750
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
751
|
-
ctx.ui.notify(
|
|
752
|
-
`Freeflow modes are inactive because Skills are disabled. Configured default mode: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). Enable Skills in /freeflow settings before changing mode.`,
|
|
753
|
-
"warning",
|
|
754
|
-
);
|
|
755
|
-
return { changed: false, error: "skills_disabled" };
|
|
756
|
-
}
|
|
757
|
-
if (VALID_MODES.has(arg)) {
|
|
758
|
-
if (inactiveModeState.effectiveMode === arg) {
|
|
759
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
760
|
-
const message = inactiveModeState.sessionMode
|
|
761
|
-
? `Freeflow is already in ${arg} mode for this Pi session. No session entry was added. Configured default remains ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}).`
|
|
762
|
-
: `Freeflow is already in ${arg} mode from the configured default (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override was created.`;
|
|
763
|
-
ctx.ui.notify(message, "info");
|
|
764
|
-
return { changed: false, modeState: inactiveModeState };
|
|
765
|
-
}
|
|
766
|
-
const modeState = await setSessionMode(arg, ctx, pi);
|
|
767
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
768
|
-
ctx.ui.notify(
|
|
769
|
-
`Freeflow mode is now ${modeState.effectiveMode} for this Pi session. Stored in Pi session history; .freeflow/local.json and .freeflow/config.json were not changed. Configured default remains ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)}).`,
|
|
770
|
-
"info",
|
|
771
|
-
);
|
|
772
|
-
return { changed: true, modeState };
|
|
773
|
-
}
|
|
774
|
-
if (RESET_MODE_ARGS.has(arg) || arg === "default") {
|
|
775
|
-
if (!inactiveModeState.sessionMode) {
|
|
776
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
777
|
-
ctx.ui.notify(
|
|
778
|
-
`Freeflow is already using the configured default: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override is active.`,
|
|
779
|
-
"info",
|
|
780
|
-
);
|
|
781
|
-
return { changed: false, modeState: inactiveModeState };
|
|
782
|
-
}
|
|
783
|
-
const modeState = await setSessionMode(null, ctx, pi);
|
|
784
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
785
|
-
ctx.ui.notify(
|
|
786
|
-
`Freeflow mode reset to configured default: ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)}). Session override cleared; .freeflow/local.json and .freeflow/config.json were not changed.`,
|
|
787
|
-
"info",
|
|
788
|
-
);
|
|
789
|
-
return { changed: true, modeState };
|
|
790
|
-
}
|
|
791
|
-
const modeState = await readModeState(ctx.cwd);
|
|
792
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
793
|
-
ctx.ui.notify(
|
|
794
|
-
`Freeflow mode is ${modeState.effectiveMode} (${describeModeState(modeState)}). Use /freeflow mode conversation, /freeflow mode workflow, /freeflow mode strict-workflow, or /freeflow mode reset.`,
|
|
795
|
-
"info",
|
|
796
|
-
);
|
|
797
|
-
return { changed: false, modeState, error: arg ? "invalid_mode" : undefined };
|
|
798
|
-
}
|