@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
|
@@ -2,19 +2,17 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export const VALID_MODES = new Set(["conversation", "workflow", "strict-workflow"]);
|
|
5
|
+
import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
|
|
6
|
+
import { supportsCognitiveRoutingModelRegistry } from "../cognitive-routing/host.js";
|
|
8
7
|
|
|
9
8
|
export const WORKFLOW_COMMANDS = [
|
|
10
9
|
{ command: "discuss", skill: "discuss" },
|
|
11
|
-
{ command: "
|
|
10
|
+
{ command: "action-selection", skill: "action-selection" },
|
|
12
11
|
{ command: "track-work", skill: "track-work" },
|
|
13
12
|
{ command: "write-spec", skill: "write-spec" },
|
|
14
13
|
{ command: "review-artifact", skill: "review-artifact" },
|
|
15
14
|
{ command: "write-plan", skill: "write-plan" },
|
|
16
15
|
{ command: "execute-work", skill: "execute-work" },
|
|
17
|
-
{ command: "execute-plan", skill: "execute-work" },
|
|
18
16
|
{ command: "simplify-code", skill: "simplify-code" },
|
|
19
17
|
{ command: "migration-work", skill: "migration-work" },
|
|
20
18
|
{ command: "diagnose-failure", skill: "diagnose-failure" },
|
|
@@ -31,6 +29,7 @@ export const WORKFLOW_COMMANDS = [
|
|
|
31
29
|
export const CONTRIBUTOR_COMMANDS = ["setup-freeflow", "write-skill", "evaluate-skill"];
|
|
32
30
|
|
|
33
31
|
export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
32
|
+
"action-selection",
|
|
34
33
|
"bypass",
|
|
35
34
|
"commit-work",
|
|
36
35
|
"decision-gate",
|
|
@@ -42,7 +41,6 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
42
41
|
"execute-work",
|
|
43
42
|
"finish-branch",
|
|
44
43
|
"handoff",
|
|
45
|
-
"mode-contract",
|
|
46
44
|
"release-work",
|
|
47
45
|
"review-artifact",
|
|
48
46
|
"review-work",
|
|
@@ -58,63 +56,114 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
58
56
|
"write-spec",
|
|
59
57
|
];
|
|
60
58
|
|
|
59
|
+
export const FREEFLOW_CAPABILITY_SKILL_NAMES = ["cognitive-routing", "context-virtualization", "conversation-history"];
|
|
60
|
+
|
|
61
61
|
export function freeflowSkillPath(skillName) {
|
|
62
62
|
return fileURLToPath(new URL(`../../../skills/${skillName}/SKILL.md`, import.meta.url));
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export function
|
|
66
|
-
return
|
|
65
|
+
export function freeflowCapabilitySkillPath(skillName) {
|
|
66
|
+
return fileURLToPath(new URL(`../../../capabilities/${skillName}/SKILL.md`, import.meta.url));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
70
|
+
const paths = FREEFLOW_MODEL_SKILL_NAMES.map((skillName) => freeflowSkillPath(skillName));
|
|
71
|
+
const capabilityStates = {
|
|
72
|
+
"cognitive-routing": capabilityState?.cognitiveRouting,
|
|
73
|
+
"context-virtualization": capabilityState?.contextVirtualization,
|
|
74
|
+
"conversation-history": capabilityState?.conversationHistory,
|
|
75
|
+
};
|
|
76
|
+
for (const skillName of FREEFLOW_CAPABILITY_SKILL_NAMES) {
|
|
77
|
+
if (capabilityStates[skillName]?.effective === true) {
|
|
78
|
+
paths.push(freeflowCapabilitySkillPath(skillName));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return paths;
|
|
67
82
|
}
|
|
68
83
|
|
|
69
|
-
type SessionCoreKey = "enabled" | "
|
|
84
|
+
type SessionCoreKey = "enabled" | "contextVirtualization" | "conversationHistory";
|
|
70
85
|
type SessionCoreOverrides = Partial<Record<SessionCoreKey, boolean>>;
|
|
71
86
|
|
|
72
|
-
const MODE_STATE_ENTRY = "freeflow-mode";
|
|
73
87
|
const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
|
|
74
|
-
const SESSION_CORE_KEYS = new Set<SessionCoreKey>(["enabled", "
|
|
75
|
-
const RESET_MODE_ARGS = new Set(["reset"]);
|
|
88
|
+
const SESSION_CORE_KEYS = new Set<SessionCoreKey>(["enabled", "contextVirtualization", "conversationHistory"]);
|
|
76
89
|
|
|
77
|
-
export const
|
|
78
|
-
export const
|
|
90
|
+
export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
|
|
91
|
+
export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
|
|
92
|
+
export const COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-cognitive-routing-runtime-state";
|
|
79
93
|
export const WORKFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-workflow-bootstrap";
|
|
94
|
+
export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-routing-bootstrap";
|
|
95
|
+
export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
|
|
80
96
|
|
|
81
97
|
let runtimeContextCache = null;
|
|
82
|
-
let currentModeOverride = null;
|
|
83
98
|
let currentSessionOverrides: SessionCoreOverrides = {};
|
|
84
|
-
|
|
99
|
+
|
|
100
|
+
export function isPromptAvailable(value: unknown): value is string {
|
|
101
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function hasUsableMandatoryPrompts(freeflowContext: any): boolean {
|
|
105
|
+
return (
|
|
106
|
+
isPromptAvailable(freeflowContext?.corePrompt) && isPromptAvailable(freeflowContext?.interactionContractPrompt)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function readPromptFile(url: URL): Promise<string | null> {
|
|
111
|
+
try {
|
|
112
|
+
const prompt = await readFile(url, "utf8");
|
|
113
|
+
return isPromptAvailable(prompt) ? prompt.trim() : null;
|
|
114
|
+
} catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
async function loadRuntimeContext(capabilityState = undefined) {
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
const freeflowEnabled = capabilityState?.enabled === true;
|
|
121
|
+
const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
|
|
122
|
+
const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
|
|
123
|
+
const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
|
|
124
|
+
const [
|
|
125
|
+
corePrompt,
|
|
126
|
+
interactionContractPrompt,
|
|
127
|
+
cognitiveRoutingPrompt,
|
|
128
|
+
contextVirtualizationPrompt,
|
|
129
|
+
conversationHistoryPrompt,
|
|
130
|
+
] = await Promise.all([
|
|
131
|
+
freeflowEnabled
|
|
132
|
+
? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
|
|
92
133
|
: Promise.resolve(null),
|
|
93
|
-
|
|
94
|
-
?
|
|
134
|
+
freeflowEnabled
|
|
135
|
+
? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
|
|
95
136
|
: Promise.resolve(null),
|
|
96
|
-
|
|
97
|
-
?
|
|
137
|
+
cognitiveRoutingEnabled
|
|
138
|
+
? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
|
|
139
|
+
: Promise.resolve(null),
|
|
140
|
+
contextVirtualizationEnabled
|
|
141
|
+
? readPromptFile(new URL("../../../runtime/prompts/context-virtualization.md", import.meta.url))
|
|
142
|
+
: Promise.resolve(null),
|
|
143
|
+
conversationHistoryEnabled
|
|
144
|
+
? readPromptFile(new URL("../../../runtime/prompts/conversation-history.md", import.meta.url))
|
|
98
145
|
: Promise.resolve(null),
|
|
99
146
|
]);
|
|
100
147
|
|
|
101
|
-
return {
|
|
148
|
+
return {
|
|
149
|
+
corePrompt,
|
|
150
|
+
interactionContractPrompt,
|
|
151
|
+
cognitiveRoutingPrompt,
|
|
152
|
+
contextVirtualizationPrompt,
|
|
153
|
+
conversationHistoryPrompt,
|
|
154
|
+
};
|
|
102
155
|
}
|
|
103
156
|
|
|
104
157
|
function runtimeContextCacheSatisfies(capabilityState) {
|
|
105
|
-
if (!runtimeContextCache)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (capabilityState?.outputRouter?.enabled === true && !runtimeContextCache.outputRouterSkill) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
158
|
+
if (!runtimeContextCache) return false;
|
|
159
|
+
const expected = {
|
|
160
|
+
corePrompt: capabilityState?.enabled === true,
|
|
161
|
+
interactionContractPrompt: capabilityState?.enabled === true,
|
|
162
|
+
cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
|
|
163
|
+
contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
|
|
164
|
+
conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
|
|
165
|
+
};
|
|
166
|
+
return Object.entries(expected).every(([key, required]) => !required || isPromptAvailable(runtimeContextCache[key]));
|
|
118
167
|
}
|
|
119
168
|
|
|
120
169
|
export async function refreshRuntimeContext(capabilityState = undefined) {
|
|
@@ -129,44 +178,34 @@ export async function getRuntimeContext(capabilityState = undefined) {
|
|
|
129
178
|
return refreshRuntimeContext(capabilityState);
|
|
130
179
|
}
|
|
131
180
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (Array.isArray(entries)) {
|
|
137
|
-
return entries;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (typeof sessionManager?.getEntries === "function") {
|
|
141
|
-
const entries = sessionManager.getEntries();
|
|
142
|
-
if (Array.isArray(entries)) {
|
|
143
|
-
return entries;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// A missing session snapshot should reload useful context rather than suppress it.
|
|
148
|
-
}
|
|
149
|
-
return [];
|
|
150
|
-
}
|
|
181
|
+
const BOOTSTRAP_COMPONENTS = Object.freeze({
|
|
182
|
+
workflow: "workflow",
|
|
183
|
+
cognitiveRouting: "cognitive-routing",
|
|
184
|
+
});
|
|
151
185
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
186
|
+
function bootstrapEntryComponents(entry) {
|
|
187
|
+
const isCustomMessage = entry?.role === "custom" || entry?.type === "custom_message" || entry?.type === "custom";
|
|
188
|
+
if (!isCustomMessage) return [];
|
|
189
|
+
if (entry.customType === FREEFLOW_BOOTSTRAP_MESSAGE_TYPE) {
|
|
190
|
+
if (Array.isArray(entry.details?.components)) return entry.details.components;
|
|
191
|
+
return [
|
|
192
|
+
...(entry.content?.includes("<!-- freeflow-bootstrap:workflow -->") ? [BOOTSTRAP_COMPONENTS.workflow] : []),
|
|
193
|
+
...(entry.content?.includes("<!-- freeflow-bootstrap:cognitive-routing -->")
|
|
194
|
+
? [BOOTSTRAP_COMPONENTS.cognitiveRouting]
|
|
195
|
+
: []),
|
|
196
|
+
];
|
|
155
197
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
(entry) => entry?.type === "custom_message" && entry?.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE,
|
|
159
|
-
);
|
|
160
|
-
if (alreadyLoaded) {
|
|
161
|
-
return undefined;
|
|
198
|
+
if (entry.customType === WORKFLOW_BOOTSTRAP_MESSAGE_TYPE) {
|
|
199
|
+
return [BOOTSTRAP_COMPONENTS.workflow];
|
|
162
200
|
}
|
|
201
|
+
if (entry.customType === COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE) {
|
|
202
|
+
return [BOOTSTRAP_COMPONENTS.cognitiveRouting];
|
|
203
|
+
}
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
163
206
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
content: `# Freeflow Workflow Bootstrap\n\n${freeflowContext.workflowSkill.trim()}`,
|
|
167
|
-
display: false,
|
|
168
|
-
details: { skill: "workflow", source: "first-turn-bootstrap" },
|
|
169
|
-
};
|
|
207
|
+
export function filterBootstrapMessage(message) {
|
|
208
|
+
return bootstrapEntryComponents(message).length === 0 ? message : undefined;
|
|
170
209
|
}
|
|
171
210
|
|
|
172
211
|
function isRecord(value) {
|
|
@@ -174,30 +213,16 @@ function isRecord(value) {
|
|
|
174
213
|
}
|
|
175
214
|
|
|
176
215
|
function validateCoreConfigFields(value) {
|
|
177
|
-
if (value.defaultMode !== undefined && !VALID_MODES.has(value.defaultMode)) {
|
|
178
|
-
return `invalid defaultMode: ${JSON.stringify(value.defaultMode)}`;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
216
|
if (value.enabled !== undefined && typeof value.enabled !== "boolean") {
|
|
182
217
|
return "enabled must be a boolean";
|
|
183
218
|
}
|
|
184
219
|
|
|
185
|
-
if (value.
|
|
186
|
-
return "
|
|
220
|
+
if (value.contextVirtualization !== undefined && typeof value.contextVirtualization !== "boolean") {
|
|
221
|
+
return "contextVirtualization must be a boolean";
|
|
187
222
|
}
|
|
188
223
|
|
|
189
|
-
if (value.
|
|
190
|
-
|
|
191
|
-
return "skills must be an object";
|
|
192
|
-
}
|
|
193
|
-
for (const key of Object.keys(value.skills)) {
|
|
194
|
-
if (key !== "enabled") {
|
|
195
|
-
return `unsupported skills config key: ${key}`;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (value.skills.enabled !== undefined && typeof value.skills.enabled !== "boolean") {
|
|
199
|
-
return "skills.enabled must be a boolean";
|
|
200
|
-
}
|
|
224
|
+
if (value.conversationHistory !== undefined && typeof value.conversationHistory !== "boolean") {
|
|
225
|
+
return "conversationHistory must be a boolean";
|
|
201
226
|
}
|
|
202
227
|
|
|
203
228
|
return null;
|
|
@@ -208,14 +233,15 @@ function validateFreeflowConfigShape(value) {
|
|
|
208
233
|
return "config must be a JSON object";
|
|
209
234
|
}
|
|
210
235
|
|
|
236
|
+
// Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
|
|
211
237
|
const allowedKeys = new Set([
|
|
212
238
|
"enabled",
|
|
213
|
-
"defaultMode",
|
|
214
|
-
"interactionContract",
|
|
215
|
-
"skills",
|
|
216
239
|
"outputRouter",
|
|
217
240
|
"observedRouting",
|
|
218
241
|
"scriptTransform",
|
|
242
|
+
"cognitiveRouting",
|
|
243
|
+
"contextVirtualization",
|
|
244
|
+
"conversationHistory",
|
|
219
245
|
]);
|
|
220
246
|
for (const key of Object.keys(value)) {
|
|
221
247
|
if (!allowedKeys.has(key)) {
|
|
@@ -240,7 +266,13 @@ function validateFreeflowLocalConfigShape(value) {
|
|
|
240
266
|
return "local config must be a JSON object";
|
|
241
267
|
}
|
|
242
268
|
|
|
243
|
-
const allowedKeys = new Set([
|
|
269
|
+
const allowedKeys = new Set([
|
|
270
|
+
"enabled",
|
|
271
|
+
"processing",
|
|
272
|
+
"cognitiveRouting",
|
|
273
|
+
"contextVirtualization",
|
|
274
|
+
"conversationHistory",
|
|
275
|
+
]);
|
|
244
276
|
for (const key of Object.keys(value)) {
|
|
245
277
|
if (!allowedKeys.has(key)) {
|
|
246
278
|
return `unsupported top-level local config key: ${key}`;
|
|
@@ -317,24 +349,19 @@ function resolveLayeredValue(repository, local, key, fallback) {
|
|
|
317
349
|
|
|
318
350
|
function resolveCoreConfig(repository, local) {
|
|
319
351
|
const enabled = resolveLayeredValue(repository, local, "enabled", true);
|
|
320
|
-
const
|
|
321
|
-
const
|
|
322
|
-
const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
|
|
323
|
-
const localSkills = isRecord(local.skills) ? local.skills : {};
|
|
324
|
-
const skillsEnabled = resolveLayeredValue(repositorySkills, localSkills, "enabled", true);
|
|
352
|
+
const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
|
|
353
|
+
const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
|
|
325
354
|
|
|
326
355
|
return {
|
|
327
356
|
config: {
|
|
328
357
|
enabled: enabled.value,
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
defaultMode: defaultMode.value,
|
|
358
|
+
contextVirtualization: contextVirtualization.value,
|
|
359
|
+
conversationHistory: conversationHistory.value,
|
|
332
360
|
},
|
|
333
361
|
sources: {
|
|
334
362
|
enabled: enabled.source,
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
defaultMode: defaultMode.source,
|
|
363
|
+
contextVirtualization: contextVirtualization.source,
|
|
364
|
+
conversationHistory: conversationHistory.source,
|
|
338
365
|
},
|
|
339
366
|
};
|
|
340
367
|
}
|
|
@@ -354,22 +381,21 @@ function resolveSessionCoreConfig(layers) {
|
|
|
354
381
|
const configured = layers.coreConfig;
|
|
355
382
|
const sources = layers.sources;
|
|
356
383
|
const enabled = currentSessionOverrides.enabled;
|
|
357
|
-
const
|
|
358
|
-
const
|
|
384
|
+
const contextVirtualization = currentSessionOverrides.contextVirtualization;
|
|
385
|
+
const conversationHistory = currentSessionOverrides.conversationHistory;
|
|
359
386
|
|
|
360
387
|
return {
|
|
361
388
|
config: {
|
|
362
389
|
enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
|
|
363
|
-
|
|
364
|
-
typeof
|
|
365
|
-
|
|
366
|
-
|
|
390
|
+
contextVirtualization:
|
|
391
|
+
typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
|
|
392
|
+
conversationHistory:
|
|
393
|
+
typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
|
|
367
394
|
},
|
|
368
395
|
sources: {
|
|
369
396
|
enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
defaultMode: sources.defaultMode,
|
|
397
|
+
contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
|
|
398
|
+
conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
|
|
373
399
|
},
|
|
374
400
|
};
|
|
375
401
|
}
|
|
@@ -400,15 +426,32 @@ export async function readFreeflowConfigLayers(cwd) {
|
|
|
400
426
|
};
|
|
401
427
|
}
|
|
402
428
|
|
|
403
|
-
export async function readCapabilityState(cwd) {
|
|
429
|
+
export async function readCapabilityState(cwd, host = undefined, extensionHost = undefined) {
|
|
404
430
|
const layers = await readFreeflowConfigLayers(cwd);
|
|
405
|
-
const parsed = layers.repository.valid ? layers.repository.parsed : {};
|
|
406
|
-
const normalized = normalizeFreeflowConfig(parsed);
|
|
407
431
|
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
408
432
|
const enabled = layers.configured && effectiveCore.config.enabled;
|
|
409
|
-
const
|
|
410
|
-
const
|
|
411
|
-
const
|
|
433
|
+
const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
|
|
434
|
+
const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
|
|
435
|
+
const hostSupportsCognitiveRouting = supportsCognitiveRoutingModelRegistry(host);
|
|
436
|
+
const configuredCognitiveRouting = await resolveCognitiveRoutingState(
|
|
437
|
+
layers.repository.parsed,
|
|
438
|
+
layers.local.parsed,
|
|
439
|
+
hostSupportsCognitiveRouting ? host : undefined,
|
|
440
|
+
);
|
|
441
|
+
const disabledReason = enabled ? undefined : { code: "disabled" as const, message: "Freeflow is disabled" };
|
|
442
|
+
const childCapability = (configuredEnabled) => ({
|
|
443
|
+
enabled: configuredEnabled,
|
|
444
|
+
effective: enabled && configuredEnabled,
|
|
445
|
+
...(disabledReason ? { blockingReason: disabledReason } : {}),
|
|
446
|
+
});
|
|
447
|
+
const cognitiveRouting = enabled
|
|
448
|
+
? configuredCognitiveRouting
|
|
449
|
+
: {
|
|
450
|
+
...configuredCognitiveRouting,
|
|
451
|
+
enabled: false,
|
|
452
|
+
effective: false,
|
|
453
|
+
blockingReason: disabledReason,
|
|
454
|
+
};
|
|
412
455
|
return {
|
|
413
456
|
configured: layers.configured,
|
|
414
457
|
repositoryConfigured: layers.repositoryConfigured,
|
|
@@ -424,121 +467,34 @@ export async function readCapabilityState(cwd) {
|
|
|
424
467
|
configuredSources: layers.sources,
|
|
425
468
|
sessionOverrides: { ...currentSessionOverrides },
|
|
426
469
|
configSources: effectiveCore.sources,
|
|
427
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
428
470
|
enabled,
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
skills: {
|
|
434
|
-
enabled: skillsConfigEnabled,
|
|
435
|
-
effective: enabled && skillsConfigEnabled,
|
|
436
|
-
},
|
|
437
|
-
outputRouter: {
|
|
438
|
-
enabled: enabled && outputRouterConfigEnabled,
|
|
439
|
-
configEnabled: outputRouterConfigEnabled,
|
|
440
|
-
},
|
|
471
|
+
contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
|
|
472
|
+
conversationHistory: childCapability(conversationHistoryConfigEnabled),
|
|
473
|
+
hostSupportsCognitiveRouting,
|
|
474
|
+
cognitiveRouting,
|
|
441
475
|
};
|
|
442
476
|
}
|
|
443
477
|
|
|
444
478
|
export const readRuntimeState = readCapabilityState;
|
|
445
479
|
|
|
446
|
-
export
|
|
447
|
-
const layers = await readFreeflowConfigLayers(cwd);
|
|
448
|
-
const parsed = layers.repository.valid ? layers.repository.parsed : {};
|
|
449
|
-
const localParsed = layers.local.valid ? layers.local.parsed : {};
|
|
450
|
-
const normalized = normalizeFreeflowConfig(parsed);
|
|
451
|
-
const local = normalizeLocalFreeflowConfig(localParsed);
|
|
452
|
-
const freeflowEnabled = layers.configured && layers.coreConfig.enabled;
|
|
453
|
-
const effectiveConfig = freeflowEnabled
|
|
454
|
-
? normalized.config
|
|
455
|
-
: {
|
|
456
|
-
...normalized.config,
|
|
457
|
-
outputRouter: { ...normalized.config.outputRouter, enabled: false },
|
|
458
|
-
observedRouting: {
|
|
459
|
-
...normalized.config.observedRouting,
|
|
460
|
-
enabled: false,
|
|
461
|
-
},
|
|
462
|
-
scriptTransform: {
|
|
463
|
-
...normalized.config.scriptTransform,
|
|
464
|
-
enabled: false,
|
|
465
|
-
},
|
|
466
|
-
};
|
|
467
|
-
const configWarnings = [...normalized.warnings];
|
|
468
|
-
if (layers.repository.exists && !layers.repository.valid) {
|
|
469
|
-
configWarnings.unshift(
|
|
470
|
-
`.freeflow/config.json could not be parsed; Freeflow runtime is inactive. ${layers.repository.parseError ?? ""}`.trim(),
|
|
471
|
-
);
|
|
472
|
-
}
|
|
473
|
-
if (layers.local.exists && !layers.local.valid) {
|
|
474
|
-
configWarnings.unshift(
|
|
475
|
-
`.freeflow/local.json could not be parsed; Freeflow runtime is inactive. ${layers.local.parseError ?? ""}`.trim(),
|
|
476
|
-
);
|
|
477
|
-
}
|
|
478
|
-
return {
|
|
479
|
-
config: effectiveConfig.outputRouter,
|
|
480
|
-
freeflowConfig: effectiveConfig,
|
|
481
|
-
localConfig: local.config,
|
|
482
|
-
warnings: [...configWarnings, ...local.warnings],
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
export function notifyRouterConfigWarnings(ctx, routerConfigResult) {
|
|
487
|
-
if (!routerConfigResult.warnings.length) {
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const key = routerConfigResult.warnings.join("\n");
|
|
492
|
-
if (key === lastRouterConfigWarningKey) {
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
lastRouterConfigWarningKey = key;
|
|
497
|
-
ctx.ui.notify(`Freeflow config warning: ${routerConfigResult.warnings.join(" ")}`, "warning");
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
export function restoreModeOverride(ctx) {
|
|
501
|
-
currentModeOverride = null;
|
|
480
|
+
export function restoreSessionOverrides(ctx) {
|
|
502
481
|
currentSessionOverrides = {};
|
|
503
482
|
const entries = ctx.sessionManager?.getBranch?.() ?? ctx.sessionManager?.getEntries?.() ?? [];
|
|
504
483
|
|
|
505
484
|
for (const entry of entries) {
|
|
506
|
-
if (entry.type
|
|
507
|
-
if (entry.customType === MODE_STATE_ENTRY) {
|
|
508
|
-
const mode = entry.data?.currentMode;
|
|
509
|
-
currentModeOverride = VALID_MODES.has(mode) ? mode : null;
|
|
510
|
-
} else if (entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
485
|
+
if (entry.type === "custom" && entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
511
486
|
currentSessionOverrides = normalizeSessionOverrides(entry.data?.overrides);
|
|
512
487
|
}
|
|
513
488
|
}
|
|
514
489
|
}
|
|
515
490
|
|
|
516
|
-
export
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const sessionMode = VALID_MODES.has(currentModeOverride) ? currentModeOverride : null;
|
|
524
|
-
const resolvedMode = sessionMode ?? effectiveCore.config.defaultMode;
|
|
525
|
-
const active = layers.configured && effectiveCore.config.enabled && effectiveCore.config.skills.enabled;
|
|
526
|
-
|
|
527
|
-
return {
|
|
528
|
-
repositoryDefaultMode,
|
|
529
|
-
repositoryDefaultModeSource: VALID_MODES.has(layers.repository.parsed.defaultMode) ? "repository" : "builtin",
|
|
530
|
-
personalDefaultMode,
|
|
531
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
532
|
-
defaultModeSource: effectiveCore.sources.defaultMode,
|
|
533
|
-
currentMode: sessionMode,
|
|
534
|
-
sessionMode,
|
|
535
|
-
resolvedMode,
|
|
536
|
-
active,
|
|
537
|
-
effectiveMode: active ? resolvedMode : null,
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
export function setModeStatus(ctx, modeState, capabilityState = undefined) {
|
|
491
|
+
export function setFreeflowStatus(
|
|
492
|
+
ctx,
|
|
493
|
+
capabilityState = undefined,
|
|
494
|
+
cognitiveRoutingRuntime = undefined,
|
|
495
|
+
freeflowContext = undefined,
|
|
496
|
+
options: { cognitiveRoutingStartupPending?: boolean; startupSelectionSuppressed?: boolean } = {},
|
|
497
|
+
) {
|
|
542
498
|
if (capabilityState && !capabilityState.configured) {
|
|
543
499
|
ctx.ui.setStatus("freeflow", capabilityState.configExists ? "freeflow: config error" : "freeflow: setup needed");
|
|
544
500
|
return;
|
|
@@ -548,36 +504,59 @@ export function setModeStatus(ctx, modeState, capabilityState = undefined) {
|
|
|
548
504
|
ctx.ui.setStatus("freeflow", `freeflow: off${source}`);
|
|
549
505
|
return;
|
|
550
506
|
}
|
|
507
|
+
if (capabilityState?.enabled === true && !hasUsableMandatoryPrompts(freeflowContext)) {
|
|
508
|
+
ctx.ui.setStatus("freeflow", "freeflow: unavailable");
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
551
511
|
|
|
552
512
|
const active: string[] = [];
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
513
|
+
const cognitiveRouting = capabilityState?.cognitiveRouting;
|
|
514
|
+
const cognitiveRoutingInactive =
|
|
515
|
+
cognitiveRouting?.enabled === true && cognitiveRoutingRuntime?.runtimeStatus === "inactive";
|
|
516
|
+
const cognitiveRoutingBlocked =
|
|
517
|
+
cognitiveRouting?.enabled === true &&
|
|
518
|
+
(cognitiveRouting?.blockingReason?.code === "runtime_blocked" ||
|
|
519
|
+
cognitiveRoutingRuntime?.runtimeStatus === "blocked");
|
|
520
|
+
const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
|
|
521
|
+
const startupSelectionSuppressesCognitiveRouting = options.startupSelectionSuppressed === true;
|
|
522
|
+
if (cognitiveRoutingInactive) {
|
|
523
|
+
active.push("cognitive inactive");
|
|
524
|
+
} else if (cognitiveRoutingBlocked) {
|
|
525
|
+
active.push(`cognitive blocked · ${cognitiveRoutingRuntime?.runtimeReason ?? "runtime_blocked"}`);
|
|
526
|
+
} else if (cognitiveRoutingActive) {
|
|
527
|
+
const profile = cognitiveRoutingRuntime.activeProfile;
|
|
528
|
+
const control =
|
|
529
|
+
cognitiveRoutingRuntime.controlMode === "manual-standard" ||
|
|
530
|
+
cognitiveRoutingRuntime.controlMode === "manual-reasoning"
|
|
531
|
+
? "manual hold"
|
|
532
|
+
: "automatic";
|
|
533
|
+
active.push(`${profile} · ${control}`);
|
|
534
|
+
} else if (cognitiveRouting?.enabled === true) {
|
|
535
|
+
if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
|
|
536
|
+
active.push("cognitive blocked · runtime_disabled");
|
|
537
|
+
} else if (
|
|
538
|
+
cognitiveRouting.effective === true &&
|
|
539
|
+
cognitiveRoutingRuntime === undefined &&
|
|
540
|
+
options.cognitiveRoutingStartupPending === true &&
|
|
541
|
+
!startupSelectionSuppressesCognitiveRouting
|
|
542
|
+
) {
|
|
543
|
+
const startupProfile =
|
|
544
|
+
cognitiveRouting.sessionStart?.control === "manual"
|
|
545
|
+
? (cognitiveRouting.sessionStart.profile ?? "reasoning")
|
|
546
|
+
: "reasoning";
|
|
547
|
+
active.push(`${startupProfile} · pending`);
|
|
548
|
+
} else {
|
|
549
|
+
const reason =
|
|
550
|
+
cognitiveRouting.effective === true
|
|
551
|
+
? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
|
|
552
|
+
: (cognitiveRouting.blockingReason?.code ?? "unavailable");
|
|
553
|
+
active.push(`cognitive blocked · ${reason}`);
|
|
554
|
+
}
|
|
562
555
|
}
|
|
563
|
-
if (capabilityState?.
|
|
564
|
-
active.push("
|
|
556
|
+
if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
|
|
557
|
+
active.push("context");
|
|
565
558
|
}
|
|
566
|
-
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
function modeSourceLabel(source) {
|
|
570
|
-
if (source === "local") return "personal override";
|
|
571
|
-
if (source === "repository") return "repository default";
|
|
572
|
-
return "built-in default";
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function describeModeState(modeState) {
|
|
576
|
-
const configuredDefault = `configured default ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)})`;
|
|
577
|
-
if (modeState.sessionMode) {
|
|
578
|
-
return `session ${modeState.sessionMode}; ${configuredDefault}`;
|
|
579
|
-
}
|
|
580
|
-
return configuredDefault;
|
|
559
|
+
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "active"}`);
|
|
581
560
|
}
|
|
582
561
|
|
|
583
562
|
export function skillPrompt(skill, args) {
|
|
@@ -585,175 +564,170 @@ export function skillPrompt(skill, args) {
|
|
|
585
564
|
return trimmed ? `/skill:${skill}\n\n${trimmed}` : `/skill:${skill}`;
|
|
586
565
|
}
|
|
587
566
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (mode === "strict-workflow") {
|
|
596
|
-
return "strict-workflow mode: strongest guidance; prefer exact, recoverable routed evidence for risky work.";
|
|
597
|
-
}
|
|
598
|
-
return "workflow mode: prefer routed tools for exploration and likely-large command output.";
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
function outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState) {
|
|
602
|
-
const safetyNetText =
|
|
603
|
-
routerConfigResult.config.postToolRouting === "off"
|
|
604
|
-
? ""
|
|
605
|
-
: "\n\nOutput-router config note: large native read/bash outputs may be vaulted and replaced with labeled routed output. Use freeflow_search with the output id to recover exact content.";
|
|
606
|
-
|
|
607
|
-
return `## Loaded Output Router Skill
|
|
567
|
+
type CognitiveRoutingRuntimeSnapshot = {
|
|
568
|
+
effective?: boolean;
|
|
569
|
+
runtimeStatus?: "active" | "inactive" | "blocked";
|
|
570
|
+
runtimeReason?: unknown;
|
|
571
|
+
activeProfile?: unknown;
|
|
572
|
+
controlMode?: unknown;
|
|
573
|
+
};
|
|
608
574
|
|
|
609
|
-
|
|
575
|
+
type FreeflowContextMessage = {
|
|
576
|
+
customType?: unknown;
|
|
577
|
+
[key: string]: unknown;
|
|
578
|
+
};
|
|
610
579
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
580
|
+
function publicCognitiveRoutingControl(controlMode) {
|
|
581
|
+
if (controlMode === "automatic") return "automatic";
|
|
582
|
+
if (controlMode === "manual-standard" || controlMode === "manual-reasoning") return "manual";
|
|
583
|
+
return "unavailable";
|
|
614
584
|
}
|
|
615
585
|
|
|
616
|
-
function
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
capabilityState.configSources.interactionContract,
|
|
620
|
-
)}`;
|
|
621
|
-
const skills = `${capabilityState.skills.effective ? "enabled" : "disabled"}${sessionSuffix(
|
|
622
|
-
capabilityState.configSources.skillsEnabled,
|
|
623
|
-
)}`;
|
|
624
|
-
const outputRouter = capabilityState.outputRouter.enabled ? "enabled" : "disabled";
|
|
625
|
-
return `## Freeflow Capabilities
|
|
626
|
-
|
|
627
|
-
- Interaction contract: ${interactionContract}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
|
|
628
|
-
- Skills: ${skills}. Configure with \`/freeflow settings\` or temporarily with \`/freeflow settings session\`; inspect with \`/freeflow status\`.
|
|
629
|
-
- Output router: ${outputRouter}. Configure with \`/freeflow settings\` or \`/output-router\`; inspect with \`/output-router status\`.
|
|
630
|
-
|
|
631
|
-
Disabled capabilities are named only for status/config awareness. Capability-specific instructions and tools are active only while that capability is enabled.`;
|
|
586
|
+
function publicCognitiveRoutingProfile(activeProfile, effective) {
|
|
587
|
+
if (effective !== true) return "unavailable";
|
|
588
|
+
return activeProfile === "standard" || activeProfile === "reasoning" ? activeProfile : "unavailable";
|
|
632
589
|
}
|
|
633
590
|
|
|
634
|
-
function
|
|
635
|
-
return
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
591
|
+
function publicCapabilityStatus(capability) {
|
|
592
|
+
if (capability?.effective === true) return "active";
|
|
593
|
+
if (!capability) return "unavailable";
|
|
594
|
+
const blockingCode = capability.blockingReason?.code;
|
|
595
|
+
if (blockingCode && blockingCode !== "disabled") return "unavailable";
|
|
596
|
+
return "inactive";
|
|
640
597
|
}
|
|
641
598
|
|
|
642
|
-
function
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
## Conversation Mode Boundary
|
|
647
|
-
|
|
648
|
-
Conversation mode is active and read-only.
|
|
649
|
-
|
|
650
|
-
Do not call write, edit, or mutating tools. Do not create, delete, commit, push, or change repository, system, external, or durable state.
|
|
651
|
-
|
|
652
|
-
A mutation request does not switch mode, and an execution skill does not override this boundary. Explain that conversation mode is read-only and ask the user to switch to workflow or strict-workflow.`;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
if (mode === "strict-workflow") {
|
|
656
|
-
return `
|
|
657
|
-
|
|
658
|
-
## Strict Workflow Overlay
|
|
659
|
-
|
|
660
|
-
Strict Workflow is active. Use the adaptive Workflow, but increase decision, evidence, verification, and checkpoint pressure at high-risk or hard-to-reverse boundaries.
|
|
661
|
-
|
|
662
|
-
For work affecting security, privacy, billing, data loss, migrations, public interfaces, compatibility, deployment, or architecture:
|
|
663
|
-
|
|
664
|
-
- stop for any user-owned choice or source conflict;
|
|
665
|
-
- inspect the relevant risk surface before crossing the boundary;
|
|
666
|
-
- select only artifacts, checkpoints, and independent review that materially reduce risk;
|
|
667
|
-
- verify at the affected boundary before claiming success.
|
|
668
|
-
|
|
669
|
-
Do not manufacture ceremony for low-risk, reversible work. Strict Workflow does not authorize mutation, bypass safety, or make every implementation detail a user decision.`;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
return "";
|
|
599
|
+
function publicCognitiveRoutingStatus(capability, runtime) {
|
|
600
|
+
if (runtime?.runtimeStatus === "inactive") return "inactive";
|
|
601
|
+
return publicCapabilityStatus(capability);
|
|
673
602
|
}
|
|
674
603
|
|
|
675
|
-
function
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
604
|
+
export function freeflowRuntimeStateMessage(
|
|
605
|
+
capabilityState,
|
|
606
|
+
cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
|
|
607
|
+
freeflowContext = undefined,
|
|
608
|
+
) {
|
|
609
|
+
const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
|
|
610
|
+
const profile = publicCognitiveRoutingProfile(
|
|
611
|
+
cognitiveRoutingRuntime?.activeProfile,
|
|
612
|
+
cognitiveRoutingEffective && cognitiveRoutingRuntime?.effective === true,
|
|
613
|
+
);
|
|
614
|
+
const control =
|
|
615
|
+
profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
|
|
616
|
+
const mandatoryPromptAvailable = capabilityState?.enabled !== true || hasUsableMandatoryPrompts(freeflowContext);
|
|
617
|
+
const freeflowStatus = capabilityState?.configured
|
|
618
|
+
? capabilityState.enabled
|
|
619
|
+
? mandatoryPromptAvailable
|
|
620
|
+
? "active"
|
|
621
|
+
: "unavailable"
|
|
622
|
+
: "inactive"
|
|
623
|
+
: capabilityState?.configExists
|
|
624
|
+
? "config error"
|
|
625
|
+
: "setup needed";
|
|
689
626
|
|
|
690
|
-
|
|
691
|
-
|
|
627
|
+
return {
|
|
628
|
+
role: "custom",
|
|
629
|
+
customType: FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE,
|
|
630
|
+
content: [
|
|
631
|
+
"# Freeflow Runtime State",
|
|
632
|
+
"",
|
|
633
|
+
"This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
|
|
634
|
+
"",
|
|
635
|
+
`Freeflow: ${freeflowStatus}`,
|
|
636
|
+
"",
|
|
637
|
+
"Capabilities:",
|
|
638
|
+
`- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
|
|
639
|
+
`- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
|
|
640
|
+
`- Cognitive Routing: ${publicCognitiveRoutingStatus(capabilityState?.cognitiveRouting, cognitiveRoutingRuntime)}`,
|
|
641
|
+
"",
|
|
642
|
+
"Cognitive Routing:",
|
|
643
|
+
`- Control: \`${control}\``,
|
|
644
|
+
`- Profile: \`${profile}\``,
|
|
645
|
+
].join("\n"),
|
|
646
|
+
display: false,
|
|
647
|
+
details: { source: "provider-request-runtime-state" },
|
|
648
|
+
};
|
|
692
649
|
}
|
|
693
650
|
|
|
694
|
-
function
|
|
695
|
-
return
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
Session mode override: \`${modeState.sessionMode ?? "none"}\`.
|
|
701
|
-
Resolved mode: \`${modeState.resolvedMode}\` (inactive because Skills are disabled).
|
|
702
|
-
Effective Freeflow mode: \`none\`.
|
|
703
|
-
|
|
704
|
-
Freeflow workflow modes are dormant until Skills are enabled with \`/freeflow settings\`.`;
|
|
651
|
+
export function withoutFreeflowRuntimeState(messages: readonly FreeflowContextMessage[] | undefined) {
|
|
652
|
+
return (Array.isArray(messages) ? messages : []).filter(
|
|
653
|
+
(message) =>
|
|
654
|
+
message?.customType !== FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
|
|
655
|
+
message?.customType !== COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
|
|
656
|
+
);
|
|
705
657
|
}
|
|
706
658
|
|
|
707
|
-
function
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
${inactiveModeContext(modeState)}
|
|
714
|
-
|
|
715
|
-
${capabilityContext(capabilityState)}
|
|
659
|
+
function lastUserMessageIndex(messages: readonly FreeflowContextMessage[]): number {
|
|
660
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
661
|
+
if (messages[index]?.role === "user") return index;
|
|
662
|
+
}
|
|
663
|
+
return -1;
|
|
664
|
+
}
|
|
716
665
|
|
|
717
|
-
|
|
666
|
+
function insertRuntimeStateBeforeLatestUser(
|
|
667
|
+
messages: readonly FreeflowContextMessage[],
|
|
668
|
+
runtimeState: FreeflowContextMessage,
|
|
669
|
+
): FreeflowContextMessage[] {
|
|
670
|
+
const latestUserIndex = lastUserMessageIndex(messages);
|
|
671
|
+
if (latestUserIndex < 0) return [...messages, runtimeState];
|
|
672
|
+
return [...messages.slice(0, latestUserIndex), runtimeState, ...messages.slice(latestUserIndex)];
|
|
718
673
|
}
|
|
719
674
|
|
|
720
|
-
export function
|
|
721
|
-
|
|
675
|
+
export function withFreeflowRuntimeState(
|
|
676
|
+
messages: readonly FreeflowContextMessage[] | undefined,
|
|
677
|
+
capabilityState,
|
|
678
|
+
cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
|
|
679
|
+
freeflowContext = undefined,
|
|
680
|
+
options: { force?: boolean } = {},
|
|
681
|
+
) {
|
|
682
|
+
const source = Array.isArray(messages) ? messages : [];
|
|
683
|
+
const runtimeState = freeflowRuntimeStateMessage(capabilityState, cognitiveRoutingRuntime, freeflowContext);
|
|
684
|
+
const runtimeStateMessages = source.filter(
|
|
685
|
+
(message) =>
|
|
686
|
+
message?.customType === FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE ||
|
|
687
|
+
message?.customType === COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
|
|
688
|
+
);
|
|
689
|
+
const withoutRuntimeState = withoutFreeflowRuntimeState(source);
|
|
690
|
+
const expectedRuntimeStateIndex = lastUserMessageIndex(withoutRuntimeState);
|
|
691
|
+
const runtimeStateIndex = source.findIndex((message) => message?.customType === FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE);
|
|
692
|
+
const unchanged =
|
|
693
|
+
options.force !== true &&
|
|
694
|
+
runtimeStateMessages.length === 1 &&
|
|
695
|
+
runtimeStateMessages[0]?.customType === FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE &&
|
|
696
|
+
runtimeStateMessages[0]?.content === runtimeState.content &&
|
|
697
|
+
runtimeStateIndex === (expectedRuntimeStateIndex < 0 ? withoutRuntimeState.length : expectedRuntimeStateIndex);
|
|
698
|
+
if (unchanged) return source;
|
|
699
|
+
return insertRuntimeStateBeforeLatestUser(withoutRuntimeState, runtimeState);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
export function runtimeContext(freeflowContext, capabilityState) {
|
|
703
|
+
if (
|
|
704
|
+
capabilityState?.configured !== true ||
|
|
705
|
+
capabilityState?.enabled !== true ||
|
|
706
|
+
!hasUsableMandatoryPrompts(freeflowContext)
|
|
707
|
+
) {
|
|
722
708
|
return "";
|
|
723
709
|
}
|
|
724
710
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
711
|
+
const blocks = [freeflowContext.corePrompt.trim(), freeflowContext.interactionContractPrompt.trim()];
|
|
712
|
+
if (
|
|
713
|
+
capabilityState.cognitiveRouting?.effective === true &&
|
|
714
|
+
isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)
|
|
715
|
+
) {
|
|
716
|
+
blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
|
|
731
717
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
718
|
+
if (
|
|
719
|
+
capabilityState.contextVirtualization?.effective === true &&
|
|
720
|
+
isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
|
|
721
|
+
) {
|
|
722
|
+
blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
|
|
735
723
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
? `\n\n${outputRouterContext(modeState, freeflowContext, routerConfigResult, capabilityState)}`
|
|
744
|
-
: "";
|
|
745
|
-
|
|
746
|
-
return `# Freeflow Runtime Context
|
|
747
|
-
|
|
748
|
-
Freeflow Pi extension loaded this before the agent turn.
|
|
749
|
-
Runtime delivery: confirmed for this Pi \`before_agent_start\` invocation.
|
|
750
|
-
These instructions are context-loading only. They do not override user instructions, repo instructions, or host safety and approval policy.
|
|
751
|
-
|
|
752
|
-
${modeText}
|
|
753
|
-
|
|
754
|
-
${capabilityContext(capabilityState)}${interactionContractText}${routerText}
|
|
755
|
-
|
|
756
|
-
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.`;
|
|
724
|
+
if (
|
|
725
|
+
capabilityState.conversationHistory?.effective === true &&
|
|
726
|
+
isPromptAvailable(freeflowContext.conversationHistoryPrompt)
|
|
727
|
+
) {
|
|
728
|
+
blocks.push(freeflowContext.conversationHistoryPrompt.trim());
|
|
729
|
+
}
|
|
730
|
+
return blocks.filter(Boolean).join("\n\n");
|
|
757
731
|
}
|
|
758
732
|
|
|
759
733
|
export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean | null, ctx, pi) {
|
|
@@ -779,117 +753,25 @@ export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean
|
|
|
779
753
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: { ...currentSessionOverrides } });
|
|
780
754
|
return {
|
|
781
755
|
changed: true,
|
|
782
|
-
reloadRequired: key === "enabled"
|
|
756
|
+
reloadRequired: key === "enabled",
|
|
783
757
|
sessionOverrides: { ...currentSessionOverrides },
|
|
784
|
-
capabilityState: await readCapabilityState(ctx.cwd),
|
|
758
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
785
759
|
};
|
|
786
760
|
}
|
|
787
761
|
|
|
788
762
|
export async function resetSessionOverrides(ctx, pi) {
|
|
789
763
|
const hadCoreOverrides = Object.keys(currentSessionOverrides).length > 0;
|
|
790
|
-
const reloadRequired =
|
|
791
|
-
Object.hasOwn(currentSessionOverrides, "enabled") || Object.hasOwn(currentSessionOverrides, "skillsEnabled");
|
|
792
|
-
const hadModeOverride = VALID_MODES.has(currentModeOverride);
|
|
764
|
+
const reloadRequired = Object.hasOwn(currentSessionOverrides, "enabled");
|
|
793
765
|
|
|
794
766
|
if (hadCoreOverrides) {
|
|
795
767
|
currentSessionOverrides = {};
|
|
796
768
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: {} });
|
|
797
769
|
}
|
|
798
|
-
if (hadModeOverride) {
|
|
799
|
-
await setSessionMode(null, ctx, pi);
|
|
800
|
-
}
|
|
801
770
|
|
|
802
771
|
return {
|
|
803
|
-
changed: hadCoreOverrides
|
|
772
|
+
changed: hadCoreOverrides,
|
|
804
773
|
reloadRequired,
|
|
805
774
|
sessionOverrides: { ...currentSessionOverrides },
|
|
806
|
-
|
|
775
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
807
776
|
};
|
|
808
777
|
}
|
|
809
|
-
|
|
810
|
-
export async function setSessionMode(mode, ctx, pi) {
|
|
811
|
-
const nextMode = mode === "default" || mode === "reset" || mode === null ? null : mode;
|
|
812
|
-
if (nextMode !== null && !VALID_MODES.has(nextMode)) {
|
|
813
|
-
throw new Error(`Invalid Freeflow mode: ${String(mode)}`);
|
|
814
|
-
}
|
|
815
|
-
currentModeOverride = nextMode;
|
|
816
|
-
pi?.appendEntry?.(MODE_STATE_ENTRY, { currentMode: nextMode });
|
|
817
|
-
return readModeState(ctx.cwd);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
export async function handleModeCommand(args, ctx, pi) {
|
|
821
|
-
const arg = args?.trim();
|
|
822
|
-
const capabilityState = await readCapabilityState(ctx.cwd);
|
|
823
|
-
const inactiveModeState = await readModeState(ctx.cwd);
|
|
824
|
-
|
|
825
|
-
if (!capabilityState.configured) {
|
|
826
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
827
|
-
ctx.ui.notify(
|
|
828
|
-
"Freeflow is installed but this repo is not set up. Run /setup-freeflow before changing mode.",
|
|
829
|
-
"warning",
|
|
830
|
-
);
|
|
831
|
-
return { changed: false, error: "not_configured" };
|
|
832
|
-
}
|
|
833
|
-
if (!capabilityState.enabled) {
|
|
834
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
835
|
-
ctx.ui.notify(
|
|
836
|
-
"Freeflow is disabled for this repo. Use /freeflow enable or /freeflow settings to re-enable it.",
|
|
837
|
-
"warning",
|
|
838
|
-
);
|
|
839
|
-
return { changed: false, error: "freeflow_disabled" };
|
|
840
|
-
}
|
|
841
|
-
if (!capabilityState.skills.effective) {
|
|
842
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
843
|
-
ctx.ui.notify(
|
|
844
|
-
`Freeflow modes are inactive because Skills are disabled. Configured default mode: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). Enable Skills in /freeflow settings before changing mode.`,
|
|
845
|
-
"warning",
|
|
846
|
-
);
|
|
847
|
-
return { changed: false, error: "skills_disabled" };
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
if (VALID_MODES.has(arg)) {
|
|
851
|
-
if (inactiveModeState.effectiveMode === arg) {
|
|
852
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
853
|
-
const message = inactiveModeState.sessionMode
|
|
854
|
-
? `Freeflow is already in ${arg} mode for this Pi session. No session entry was added. Configured default remains ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}).`
|
|
855
|
-
: `Freeflow is already in ${arg} mode from the configured default (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override was created.`;
|
|
856
|
-
ctx.ui.notify(message, "info");
|
|
857
|
-
return { changed: false, modeState: inactiveModeState };
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
const modeState = await setSessionMode(arg, ctx, pi);
|
|
861
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
862
|
-
ctx.ui.notify(
|
|
863
|
-
`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)}).`,
|
|
864
|
-
"info",
|
|
865
|
-
);
|
|
866
|
-
return { changed: true, modeState };
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
if (RESET_MODE_ARGS.has(arg) || arg === "default") {
|
|
870
|
-
if (!inactiveModeState.sessionMode) {
|
|
871
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
872
|
-
ctx.ui.notify(
|
|
873
|
-
`Freeflow is already using the configured default: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override is active.`,
|
|
874
|
-
"info",
|
|
875
|
-
);
|
|
876
|
-
return { changed: false, modeState: inactiveModeState };
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
const modeState = await setSessionMode(null, ctx, pi);
|
|
880
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
881
|
-
ctx.ui.notify(
|
|
882
|
-
`Freeflow mode reset to configured default: ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)}). Session override cleared; .freeflow/local.json and .freeflow/config.json were not changed.`,
|
|
883
|
-
"info",
|
|
884
|
-
);
|
|
885
|
-
return { changed: true, modeState };
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
const modeState = await readModeState(ctx.cwd);
|
|
889
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
890
|
-
ctx.ui.notify(
|
|
891
|
-
`Freeflow mode is ${modeState.effectiveMode} (${describeModeState(modeState)}). Use /freeflow mode conversation, /freeflow mode workflow, /freeflow mode strict-workflow, or /freeflow mode reset.`,
|
|
892
|
-
"info",
|
|
893
|
-
);
|
|
894
|
-
return { changed: false, modeState, error: arg ? "invalid_mode" : undefined };
|
|
895
|
-
}
|