@hassangameryt/freeflow 0.6.0 → 0.7.1
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 +3 -2
- package/.codex-plugin/plugin.json +5 -6
- package/.cursor-plugin/plugin.json +25 -0
- package/README.md +66 -56
- package/capabilities/cognitive-routing/SKILL.md +288 -130
- package/com.github.copilot/hooks/hooks.json +11 -0
- package/command-surface.json +0 -24
- package/gemini-extension.json +5 -0
- package/hooks/adapters/claude-session-start.mjs +16 -0
- package/hooks/adapters/codex-session-start.mjs +16 -0
- package/hooks/adapters/copilot-session-start.mjs +13 -0
- package/hooks/adapters/cursor-session-start.mjs +13 -0
- package/hooks/adapters/gemini-session-start.mjs +15 -0
- package/hooks/claude/hooks.json +18 -0
- package/hooks/codex/hooks.json +18 -0
- package/hooks/cursor/hooks.json +9 -0
- package/hooks/freeflow-runtime-context.mjs +3 -650
- package/hooks/hooks.json +4 -30
- package/hooks/shared/runtime-context.mjs +210 -0
- package/hooks/tests/check-host-adapters.test.mjs +82 -0
- package/hooks/tests/check-runtime-context-hook.sh +140 -320
- package/package.json +20 -4
- package/pi-extension/dist/cognitive-routing/commands.js +3 -3
- package/pi-extension/dist/cognitive-routing/config.js +16 -20
- package/pi-extension/dist/cognitive-routing/controller.js +478 -48
- package/pi-extension/dist/cognitive-routing/history.js +12 -0
- package/pi-extension/dist/cognitive-routing/host.js +74 -12
- 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/tool.js +1 -0
- package/pi-extension/dist/cognitive-routing/types.js +1 -1
- package/pi-extension/dist/index.js +236 -219
- package/pi-extension/dist/runtime/runtime-context.js +126 -286
- package/pi-extension/dist/settings/settings-ui.js +52 -336
- package/pi-extension/src/cognitive-routing/commands.ts +15 -5
- package/pi-extension/src/cognitive-routing/config.ts +16 -20
- package/pi-extension/src/cognitive-routing/controller.ts +561 -51
- package/pi-extension/src/cognitive-routing/history.ts +12 -0
- package/pi-extension/src/cognitive-routing/host.ts +110 -16
- 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/tool.ts +1 -0
- package/pi-extension/src/cognitive-routing/types.ts +1 -1
- package/pi-extension/src/index.ts +249 -239
- package/pi-extension/src/runtime/runtime-context.ts +129 -305
- package/pi-extension/src/settings/settings-ui.ts +53 -371
- package/pi-extension/tests/cognitive-routing/commands.test.js +1 -1
- package/pi-extension/tests/cognitive-routing/controller.test.js +69 -40
- package/pi-extension/tests/cognitive-routing/extension-lifecycle.test.js +128 -57
- 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 +47 -4
- package/pi-extension/tests/integration/mode-free-core.test.js +218 -0
- package/pi-extension/tests/integration/pi-extension.test.js +430 -2478
- package/pi-extension/tests/integration/prompt-architecture.test.js +124 -79
- package/pi-extension/tests/integration/unaffected-regressions.test.js +411 -0
- package/plugin.json +33 -0
- package/runtime/prompts/cognitive-routing.md +5 -4
- package/runtime/prompts/conversation-history.md +1 -1
- package/runtime/prompts/core.md +77 -6
- package/runtime/prompts/interaction-contract.md +6 -2
- package/skills/action-selection/SKILL.md +93 -44
- package/skills/action-selection/references/trajectory-stalls.md +71 -0
- package/skills/bypass/SKILL.md +109 -39
- 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 +208 -43
- 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 +127 -173
- package/skills/design-for-depth/references/state-and-failure-boundaries.md +136 -0
- package/skills/diagnose-failure/SKILL.md +198 -52
- package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +19 -5
- package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +13 -5
- package/skills/discuss/SKILL.md +118 -76
- package/skills/discuss/references/discussion-continuity.md +84 -32
- package/skills/evaluate-skill/SKILL.md +166 -52
- package/skills/evaluate-skill/references/evaluation-definition-schema.md +2 -2
- package/skills/evaluate-skill/references/evaluation-design.md +56 -30
- package/skills/evaluate-skill/references/execution-and-evidence.md +1 -1
- package/skills/evaluate-skill/references/review-and-revision.md +62 -21
- package/skills/execute-work/SKILL.md +98 -59
- package/skills/execute-work/references/code-practices.md +4 -4
- package/skills/execute-work/references/execute-work-edges.md +42 -22
- package/skills/review-artifact/SKILL.md +132 -71
- package/skills/review-artifact/references/adjudicate-artifact-review.md +101 -0
- package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +52 -41
- package/skills/review-work/SKILL.md +115 -72
- package/skills/review-work/references/adjudicate-work-review.md +97 -0
- package/skills/review-work/references/independent-work-reviewer-contract.md +40 -35
- package/skills/review-work/references/security-risk-lens.md +17 -15
- package/skills/setup-freeflow/SKILL.md +14 -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 +108 -41
- package/skills/tdd/references/test-design.md +1 -1
- package/skills/track-work/SKILL.md +133 -300
- 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 +27 -430
- package/skills/track-work/scripts/working-record.mjs +292 -98
- package/skills/verify-work/SKILL.md +46 -20
- package/skills/verify-work/references/browser-runtime-evidence.md +1 -1
- package/skills/verify-work/references/integration-evidence.md +1 -7
- package/skills/verify-work/references/performance-evidence.md +1 -1
- package/skills/workflow/SKILL.md +110 -80
- package/skills/workflow/references/domain-skill-composition.md +24 -18
- package/skills/write-skill/SKILL.md +218 -62
- 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 +91 -41
- package/skills/write-skill/references/skill-dependency-graphs.md +190 -0
- package/runtime/prompts/skills.md +0 -65
- package/skills/mode-contract/SKILL.md +0 -104
- package/skills/track-work/scripts/lib/codec.mjs +0 -570
- package/skills/track-work/scripts/lib/commands.mjs +0 -568
- package/skills/track-work/scripts/lib/contract.mjs +0 -303
- package/skills/track-work/scripts/lib/model.mjs +0 -506
- package/skills/track-work/scripts/lib/operations.mjs +0 -965
- package/skills/track-work/scripts/lib/record-store.mjs +0 -264
- package/skills/track-work/scripts/lib/result.mjs +0 -37
- package/skills/track-work/scripts/lib/rewrites.mjs +0 -740
- package/skills/track-work/scripts/lib/schema.mjs +0 -277
- package/skills/track-work/scripts/lib/source-inventory.mjs +0 -162
- package/skills/track-work/scripts/lib/workspace.mjs +0 -134
|
@@ -2,8 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
|
|
5
|
-
import {
|
|
6
|
-
export const VALID_MODES = new Set(["conversation", "workflow", "strict-workflow"]);
|
|
5
|
+
import { supportsCognitiveRoutingModelRegistry } from "../cognitive-routing/host.js";
|
|
7
6
|
export const WORKFLOW_COMMANDS = [
|
|
8
7
|
{ command: "discuss", skill: "discuss" },
|
|
9
8
|
{ command: "action-selection", skill: "action-selection" },
|
|
@@ -38,7 +37,6 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
38
37
|
"execute-work",
|
|
39
38
|
"finish-branch",
|
|
40
39
|
"handoff",
|
|
41
|
-
"mode-contract",
|
|
42
40
|
"release-work",
|
|
43
41
|
"review-artifact",
|
|
44
42
|
"review-work",
|
|
@@ -74,16 +72,8 @@ export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
|
74
72
|
}
|
|
75
73
|
return paths;
|
|
76
74
|
}
|
|
77
|
-
const MODE_STATE_ENTRY = "freeflow-mode";
|
|
78
75
|
const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
|
|
79
|
-
const SESSION_CORE_KEYS = new Set([
|
|
80
|
-
"enabled",
|
|
81
|
-
"interactionContract",
|
|
82
|
-
"skillsEnabled",
|
|
83
|
-
"contextVirtualization",
|
|
84
|
-
"conversationHistory",
|
|
85
|
-
]);
|
|
86
|
-
const RESET_MODE_ARGS = new Set(["reset"]);
|
|
76
|
+
const SESSION_CORE_KEYS = new Set(["enabled", "contextVirtualization", "conversationHistory"]);
|
|
87
77
|
export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
|
|
88
78
|
export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
|
|
89
79
|
export const COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-cognitive-routing-runtime-state";
|
|
@@ -91,26 +81,31 @@ export const WORKFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-workflow-bootstrap";
|
|
|
91
81
|
export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-routing-bootstrap";
|
|
92
82
|
export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
|
|
93
83
|
let runtimeContextCache = null;
|
|
94
|
-
let currentModeOverride = null;
|
|
95
84
|
let currentSessionOverrides = {};
|
|
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
|
+
}
|
|
96
93
|
async function readPromptFile(url) {
|
|
97
94
|
try {
|
|
98
|
-
|
|
95
|
+
const prompt = await readFile(url, "utf8");
|
|
96
|
+
return isPromptAvailable(prompt) ? prompt.trim() : null;
|
|
99
97
|
} catch {
|
|
100
98
|
return null;
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
async function loadRuntimeContext(capabilityState = undefined) {
|
|
104
102
|
const freeflowEnabled = capabilityState?.enabled === true;
|
|
105
|
-
const interactionContractEnabled = capabilityState?.interactionContract?.effective === true;
|
|
106
|
-
const skillsEnabled = capabilityState?.skills?.effective === true;
|
|
107
103
|
const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
|
|
108
104
|
const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
|
|
109
105
|
const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
|
|
110
106
|
const [
|
|
111
107
|
corePrompt,
|
|
112
108
|
interactionContractPrompt,
|
|
113
|
-
skillsPrompt,
|
|
114
109
|
cognitiveRoutingPrompt,
|
|
115
110
|
contextVirtualizationPrompt,
|
|
116
111
|
conversationHistoryPrompt,
|
|
@@ -118,12 +113,9 @@ async function loadRuntimeContext(capabilityState = undefined) {
|
|
|
118
113
|
freeflowEnabled
|
|
119
114
|
? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
|
|
120
115
|
: Promise.resolve(null),
|
|
121
|
-
|
|
116
|
+
freeflowEnabled
|
|
122
117
|
? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
|
|
123
118
|
: Promise.resolve(null),
|
|
124
|
-
skillsEnabled
|
|
125
|
-
? readPromptFile(new URL("../../../runtime/prompts/skills.md", import.meta.url))
|
|
126
|
-
: Promise.resolve(null),
|
|
127
119
|
cognitiveRoutingEnabled
|
|
128
120
|
? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
|
|
129
121
|
: Promise.resolve(null),
|
|
@@ -137,7 +129,6 @@ async function loadRuntimeContext(capabilityState = undefined) {
|
|
|
137
129
|
return {
|
|
138
130
|
corePrompt,
|
|
139
131
|
interactionContractPrompt,
|
|
140
|
-
skillsPrompt,
|
|
141
132
|
cognitiveRoutingPrompt,
|
|
142
133
|
contextVirtualizationPrompt,
|
|
143
134
|
conversationHistoryPrompt,
|
|
@@ -147,13 +138,12 @@ function runtimeContextCacheSatisfies(capabilityState) {
|
|
|
147
138
|
if (!runtimeContextCache) return false;
|
|
148
139
|
const expected = {
|
|
149
140
|
corePrompt: capabilityState?.enabled === true,
|
|
150
|
-
interactionContractPrompt: capabilityState?.
|
|
151
|
-
skillsPrompt: capabilityState?.skills?.effective === true,
|
|
141
|
+
interactionContractPrompt: capabilityState?.enabled === true,
|
|
152
142
|
cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
|
|
153
143
|
contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
|
|
154
144
|
conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
|
|
155
145
|
};
|
|
156
|
-
return Object.entries(expected).every(([key, required]) => !required ||
|
|
146
|
+
return Object.entries(expected).every(([key, required]) => !required || isPromptAvailable(runtimeContextCache[key]));
|
|
157
147
|
}
|
|
158
148
|
export async function refreshRuntimeContext(capabilityState = undefined) {
|
|
159
149
|
runtimeContextCache = await loadRuntimeContext(capabilityState);
|
|
@@ -196,9 +186,6 @@ function isRecord(value) {
|
|
|
196
186
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
197
187
|
}
|
|
198
188
|
function validateCoreConfigFields(value) {
|
|
199
|
-
if (value.defaultMode !== undefined && !VALID_MODES.has(value.defaultMode)) {
|
|
200
|
-
return `invalid defaultMode: ${JSON.stringify(value.defaultMode)}`;
|
|
201
|
-
}
|
|
202
189
|
if (value.enabled !== undefined && typeof value.enabled !== "boolean") {
|
|
203
190
|
return "enabled must be a boolean";
|
|
204
191
|
}
|
|
@@ -208,22 +195,6 @@ function validateCoreConfigFields(value) {
|
|
|
208
195
|
if (value.conversationHistory !== undefined && typeof value.conversationHistory !== "boolean") {
|
|
209
196
|
return "conversationHistory must be a boolean";
|
|
210
197
|
}
|
|
211
|
-
if (value.interactionContract !== undefined && typeof value.interactionContract !== "boolean") {
|
|
212
|
-
return "interactionContract must be a boolean";
|
|
213
|
-
}
|
|
214
|
-
if (value.skills !== undefined) {
|
|
215
|
-
if (!isRecord(value.skills)) {
|
|
216
|
-
return "skills must be an object";
|
|
217
|
-
}
|
|
218
|
-
for (const key of Object.keys(value.skills)) {
|
|
219
|
-
if (key !== "enabled") {
|
|
220
|
-
return `unsupported skills config key: ${key}`;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (value.skills.enabled !== undefined && typeof value.skills.enabled !== "boolean") {
|
|
224
|
-
return "skills.enabled must be a boolean";
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
198
|
return null;
|
|
228
199
|
}
|
|
229
200
|
function validateFreeflowConfigShape(value) {
|
|
@@ -233,9 +204,6 @@ function validateFreeflowConfigShape(value) {
|
|
|
233
204
|
// Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
|
|
234
205
|
const allowedKeys = new Set([
|
|
235
206
|
"enabled",
|
|
236
|
-
"defaultMode",
|
|
237
|
-
"interactionContract",
|
|
238
|
-
"skills",
|
|
239
207
|
"outputRouter",
|
|
240
208
|
"observedRouting",
|
|
241
209
|
"scriptTransform",
|
|
@@ -263,9 +231,6 @@ function validateFreeflowLocalConfigShape(value) {
|
|
|
263
231
|
}
|
|
264
232
|
const allowedKeys = new Set([
|
|
265
233
|
"enabled",
|
|
266
|
-
"defaultMode",
|
|
267
|
-
"interactionContract",
|
|
268
|
-
"skills",
|
|
269
234
|
"processing",
|
|
270
235
|
"cognitiveRouting",
|
|
271
236
|
"contextVirtualization",
|
|
@@ -339,29 +304,18 @@ function resolveLayeredValue(repository, local, key, fallback) {
|
|
|
339
304
|
}
|
|
340
305
|
function resolveCoreConfig(repository, local) {
|
|
341
306
|
const enabled = resolveLayeredValue(repository, local, "enabled", true);
|
|
342
|
-
const interactionContract = resolveLayeredValue(repository, local, "interactionContract", true);
|
|
343
307
|
const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
|
|
344
308
|
const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
|
|
345
|
-
const defaultMode = resolveLayeredValue(repository, local, "defaultMode", "workflow");
|
|
346
|
-
const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
|
|
347
|
-
const localSkills = isRecord(local.skills) ? local.skills : {};
|
|
348
|
-
const skillsEnabled = resolveLayeredValue(repositorySkills, localSkills, "enabled", true);
|
|
349
309
|
return {
|
|
350
310
|
config: {
|
|
351
311
|
enabled: enabled.value,
|
|
352
|
-
interactionContract: interactionContract.value,
|
|
353
312
|
contextVirtualization: contextVirtualization.value,
|
|
354
313
|
conversationHistory: conversationHistory.value,
|
|
355
|
-
skills: { enabled: skillsEnabled.value },
|
|
356
|
-
defaultMode: defaultMode.value,
|
|
357
314
|
},
|
|
358
315
|
sources: {
|
|
359
316
|
enabled: enabled.source,
|
|
360
|
-
interactionContract: interactionContract.source,
|
|
361
317
|
contextVirtualization: contextVirtualization.source,
|
|
362
318
|
conversationHistory: conversationHistory.source,
|
|
363
|
-
skillsEnabled: skillsEnabled.source,
|
|
364
|
-
defaultMode: defaultMode.source,
|
|
365
319
|
},
|
|
366
320
|
};
|
|
367
321
|
}
|
|
@@ -379,29 +333,20 @@ function resolveSessionCoreConfig(layers) {
|
|
|
379
333
|
const configured = layers.coreConfig;
|
|
380
334
|
const sources = layers.sources;
|
|
381
335
|
const enabled = currentSessionOverrides.enabled;
|
|
382
|
-
const interactionContract = currentSessionOverrides.interactionContract;
|
|
383
336
|
const contextVirtualization = currentSessionOverrides.contextVirtualization;
|
|
384
337
|
const conversationHistory = currentSessionOverrides.conversationHistory;
|
|
385
|
-
const skillsEnabled = currentSessionOverrides.skillsEnabled;
|
|
386
338
|
return {
|
|
387
339
|
config: {
|
|
388
340
|
enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
|
|
389
|
-
interactionContract:
|
|
390
|
-
typeof interactionContract === "boolean" ? interactionContract : configured.interactionContract,
|
|
391
341
|
contextVirtualization:
|
|
392
342
|
typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
|
|
393
343
|
conversationHistory:
|
|
394
344
|
typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
|
|
395
|
-
skills: { enabled: typeof skillsEnabled === "boolean" ? skillsEnabled : configured.skills.enabled },
|
|
396
|
-
defaultMode: configured.defaultMode,
|
|
397
345
|
},
|
|
398
346
|
sources: {
|
|
399
347
|
enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
|
|
400
|
-
interactionContract: typeof interactionContract === "boolean" ? "session" : sources.interactionContract,
|
|
401
348
|
contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
|
|
402
349
|
conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
|
|
403
|
-
skillsEnabled: typeof skillsEnabled === "boolean" ? "session" : sources.skillsEnabled,
|
|
404
|
-
defaultMode: sources.defaultMode,
|
|
405
350
|
},
|
|
406
351
|
};
|
|
407
352
|
}
|
|
@@ -433,55 +378,27 @@ export async function readCapabilityState(cwd, host = undefined, extensionHost =
|
|
|
433
378
|
const layers = await readFreeflowConfigLayers(cwd);
|
|
434
379
|
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
435
380
|
const enabled = layers.configured && effectiveCore.config.enabled;
|
|
436
|
-
const interactionContractConfigEnabled = effectiveCore.config.interactionContract;
|
|
437
|
-
const skillsConfigEnabled = effectiveCore.config.skills.enabled;
|
|
438
381
|
const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
|
|
439
382
|
const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
|
|
440
|
-
const
|
|
441
|
-
const hostSupportsCognitiveRouting = isPiFlowHost(extensionHost);
|
|
383
|
+
const hostSupportsCognitiveRouting = supportsCognitiveRoutingModelRegistry(host);
|
|
442
384
|
const configuredCognitiveRouting = await resolveCognitiveRoutingState(
|
|
443
385
|
layers.repository.parsed,
|
|
444
386
|
layers.local.parsed,
|
|
445
387
|
hostSupportsCognitiveRouting ? host : undefined,
|
|
446
388
|
);
|
|
447
|
-
const disabledReason = enabled
|
|
448
|
-
? skillsEffective
|
|
449
|
-
? undefined
|
|
450
|
-
: { code: "disabled", message: "Skills are disabled" }
|
|
451
|
-
: { code: "disabled", message: "Freeflow is disabled" };
|
|
389
|
+
const disabledReason = enabled ? undefined : { code: "disabled", message: "Freeflow is disabled" };
|
|
452
390
|
const childCapability = (configuredEnabled) => ({
|
|
453
391
|
enabled: configuredEnabled,
|
|
454
|
-
effective:
|
|
392
|
+
effective: enabled && configuredEnabled,
|
|
455
393
|
...(disabledReason ? { blockingReason: disabledReason } : {}),
|
|
456
394
|
});
|
|
457
395
|
const cognitiveRouting = enabled
|
|
458
|
-
?
|
|
459
|
-
? !hostSupportsCognitiveRouting && configuredCognitiveRouting.configValid
|
|
460
|
-
? {
|
|
461
|
-
...configuredCognitiveRouting,
|
|
462
|
-
effective: false,
|
|
463
|
-
blockingReason: {
|
|
464
|
-
code: "runtime_disabled",
|
|
465
|
-
message: "Cognitive Routing is disabled outside the PiFlow runtime",
|
|
466
|
-
},
|
|
467
|
-
}
|
|
468
|
-
: configuredCognitiveRouting
|
|
469
|
-
: {
|
|
470
|
-
...configuredCognitiveRouting,
|
|
471
|
-
effective: false,
|
|
472
|
-
blockingReason: {
|
|
473
|
-
code: "disabled",
|
|
474
|
-
message: "Skills are disabled",
|
|
475
|
-
},
|
|
476
|
-
}
|
|
396
|
+
? configuredCognitiveRouting
|
|
477
397
|
: {
|
|
478
398
|
...configuredCognitiveRouting,
|
|
479
399
|
enabled: false,
|
|
480
400
|
effective: false,
|
|
481
|
-
blockingReason:
|
|
482
|
-
code: "disabled",
|
|
483
|
-
message: "Freeflow is disabled",
|
|
484
|
-
},
|
|
401
|
+
blockingReason: disabledReason,
|
|
485
402
|
};
|
|
486
403
|
return {
|
|
487
404
|
configured: layers.configured,
|
|
@@ -498,16 +415,7 @@ export async function readCapabilityState(cwd, host = undefined, extensionHost =
|
|
|
498
415
|
configuredSources: layers.sources,
|
|
499
416
|
sessionOverrides: { ...currentSessionOverrides },
|
|
500
417
|
configSources: effectiveCore.sources,
|
|
501
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
502
418
|
enabled,
|
|
503
|
-
interactionContract: {
|
|
504
|
-
enabled: interactionContractConfigEnabled,
|
|
505
|
-
effective: enabled && interactionContractConfigEnabled,
|
|
506
|
-
},
|
|
507
|
-
skills: {
|
|
508
|
-
enabled: skillsConfigEnabled,
|
|
509
|
-
effective: enabled && skillsConfigEnabled,
|
|
510
|
-
},
|
|
511
419
|
contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
|
|
512
420
|
conversationHistory: childCapability(conversationHistoryConfigEnabled),
|
|
513
421
|
hostSupportsCognitiveRouting,
|
|
@@ -515,48 +423,20 @@ export async function readCapabilityState(cwd, host = undefined, extensionHost =
|
|
|
515
423
|
};
|
|
516
424
|
}
|
|
517
425
|
export const readRuntimeState = readCapabilityState;
|
|
518
|
-
export function
|
|
519
|
-
currentModeOverride = null;
|
|
426
|
+
export function restoreSessionOverrides(ctx) {
|
|
520
427
|
currentSessionOverrides = {};
|
|
521
428
|
const entries = ctx.sessionManager?.getBranch?.() ?? ctx.sessionManager?.getEntries?.() ?? [];
|
|
522
429
|
for (const entry of entries) {
|
|
523
|
-
if (entry.type
|
|
524
|
-
if (entry.customType === MODE_STATE_ENTRY) {
|
|
525
|
-
const mode = entry.data?.currentMode;
|
|
526
|
-
currentModeOverride = VALID_MODES.has(mode) ? mode : null;
|
|
527
|
-
} else if (entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
430
|
+
if (entry.type === "custom" && entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
528
431
|
currentSessionOverrides = normalizeSessionOverrides(entry.data?.overrides);
|
|
529
432
|
}
|
|
530
433
|
}
|
|
531
434
|
}
|
|
532
|
-
export
|
|
533
|
-
const layers = await readFreeflowConfigLayers(cwd);
|
|
534
|
-
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
535
|
-
const repositoryDefaultMode = VALID_MODES.has(layers.repository.parsed.defaultMode)
|
|
536
|
-
? layers.repository.parsed.defaultMode
|
|
537
|
-
: "workflow";
|
|
538
|
-
const personalDefaultMode = VALID_MODES.has(layers.local.parsed.defaultMode) ? layers.local.parsed.defaultMode : null;
|
|
539
|
-
const sessionMode = VALID_MODES.has(currentModeOverride) ? currentModeOverride : null;
|
|
540
|
-
const resolvedMode = sessionMode ?? effectiveCore.config.defaultMode;
|
|
541
|
-
const active = layers.configured && effectiveCore.config.enabled && effectiveCore.config.skills.enabled;
|
|
542
|
-
return {
|
|
543
|
-
repositoryDefaultMode,
|
|
544
|
-
repositoryDefaultModeSource: VALID_MODES.has(layers.repository.parsed.defaultMode) ? "repository" : "builtin",
|
|
545
|
-
personalDefaultMode,
|
|
546
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
547
|
-
defaultModeSource: effectiveCore.sources.defaultMode,
|
|
548
|
-
currentMode: sessionMode,
|
|
549
|
-
sessionMode,
|
|
550
|
-
resolvedMode,
|
|
551
|
-
active,
|
|
552
|
-
effectiveMode: active ? resolvedMode : null,
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
export function setModeStatus(
|
|
435
|
+
export function setFreeflowStatus(
|
|
556
436
|
ctx,
|
|
557
|
-
modeState,
|
|
558
437
|
capabilityState = undefined,
|
|
559
438
|
cognitiveRoutingRuntime = undefined,
|
|
439
|
+
freeflowContext = undefined,
|
|
560
440
|
options = {},
|
|
561
441
|
) {
|
|
562
442
|
if (capabilityState && !capabilityState.configured) {
|
|
@@ -568,22 +448,25 @@ export function setModeStatus(
|
|
|
568
448
|
ctx.ui.setStatus("freeflow", `freeflow: off${source}`);
|
|
569
449
|
return;
|
|
570
450
|
}
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
} else if (capabilityState?.configSources?.interactionContract === "session") {
|
|
575
|
-
active.push("interaction off (session)");
|
|
576
|
-
}
|
|
577
|
-
if (capabilityState?.skills.effective) {
|
|
578
|
-
active.push(`${modeState.effectiveMode}${modeState.currentMode ? " (session)" : ""}`);
|
|
579
|
-
} else if (capabilityState?.configSources?.skillsEnabled === "session") {
|
|
580
|
-
active.push("skills off (session)");
|
|
451
|
+
if (capabilityState?.enabled === true && !hasUsableMandatoryPrompts(freeflowContext)) {
|
|
452
|
+
ctx.ui.setStatus("freeflow", "freeflow: unavailable");
|
|
453
|
+
return;
|
|
581
454
|
}
|
|
455
|
+
const active = [];
|
|
582
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");
|
|
583
463
|
const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
|
|
584
|
-
const startupSelectionSuppressesCognitiveRouting =
|
|
585
|
-
|
|
586
|
-
|
|
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) {
|
|
587
470
|
const profile = cognitiveRoutingRuntime.activeProfile;
|
|
588
471
|
const control =
|
|
589
472
|
cognitiveRoutingRuntime.controlMode === "manual-standard" ||
|
|
@@ -593,18 +476,21 @@ export function setModeStatus(
|
|
|
593
476
|
active.push(`${profile} · ${control}`);
|
|
594
477
|
} else if (cognitiveRouting?.enabled === true) {
|
|
595
478
|
if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
|
|
596
|
-
active.push("cognitive
|
|
479
|
+
active.push("cognitive blocked · runtime_disabled");
|
|
597
480
|
} else if (
|
|
598
481
|
cognitiveRouting.effective === true &&
|
|
599
482
|
cognitiveRoutingRuntime === undefined &&
|
|
600
483
|
options.cognitiveRoutingStartupPending === true &&
|
|
601
484
|
!startupSelectionSuppressesCognitiveRouting
|
|
602
485
|
) {
|
|
603
|
-
const startupProfile =
|
|
486
|
+
const startupProfile =
|
|
487
|
+
cognitiveRouting.sessionStart?.control === "manual"
|
|
488
|
+
? (cognitiveRouting.sessionStart.profile ?? "reasoning")
|
|
489
|
+
: "reasoning";
|
|
604
490
|
active.push(`${startupProfile} · pending`);
|
|
605
491
|
} else {
|
|
606
492
|
const reason =
|
|
607
|
-
cognitiveRouting
|
|
493
|
+
cognitiveRouting.effective === true
|
|
608
494
|
? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
|
|
609
495
|
: (cognitiveRouting.blockingReason?.code ?? "unavailable");
|
|
610
496
|
active.push(`cognitive blocked · ${reason}`);
|
|
@@ -613,19 +499,7 @@ export function setModeStatus(
|
|
|
613
499
|
if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
|
|
614
500
|
active.push("context");
|
|
615
501
|
}
|
|
616
|
-
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "
|
|
617
|
-
}
|
|
618
|
-
function modeSourceLabel(source) {
|
|
619
|
-
if (source === "local") return "personal override";
|
|
620
|
-
if (source === "repository") return "repository default";
|
|
621
|
-
return "built-in default";
|
|
622
|
-
}
|
|
623
|
-
function describeModeState(modeState) {
|
|
624
|
-
const configuredDefault = `configured default ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)})`;
|
|
625
|
-
if (modeState.sessionMode) {
|
|
626
|
-
return `session ${modeState.sessionMode}; ${configuredDefault}`;
|
|
627
|
-
}
|
|
628
|
-
return configuredDefault;
|
|
502
|
+
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "active"}`);
|
|
629
503
|
}
|
|
630
504
|
export function skillPrompt(skill, args) {
|
|
631
505
|
const trimmed = args?.trim();
|
|
@@ -647,7 +521,15 @@ function publicCapabilityStatus(capability) {
|
|
|
647
521
|
if (blockingCode && blockingCode !== "disabled") return "unavailable";
|
|
648
522
|
return "inactive";
|
|
649
523
|
}
|
|
650
|
-
|
|
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
|
+
) {
|
|
651
533
|
const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
|
|
652
534
|
const profile = publicCognitiveRoutingProfile(
|
|
653
535
|
cognitiveRoutingRuntime?.activeProfile,
|
|
@@ -655,8 +537,16 @@ export function freeflowRuntimeStateMessage(modeState, capabilityState, cognitiv
|
|
|
655
537
|
);
|
|
656
538
|
const control =
|
|
657
539
|
profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
|
|
658
|
-
const
|
|
659
|
-
const
|
|
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";
|
|
660
550
|
return {
|
|
661
551
|
role: "custom",
|
|
662
552
|
customType: FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE,
|
|
@@ -665,15 +555,12 @@ export function freeflowRuntimeStateMessage(modeState, capabilityState, cognitiv
|
|
|
665
555
|
"",
|
|
666
556
|
"This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
|
|
667
557
|
"",
|
|
668
|
-
`
|
|
669
|
-
`Active mode: \`${activeMode}\``,
|
|
558
|
+
`Freeflow: ${freeflowStatus}`,
|
|
670
559
|
"",
|
|
671
560
|
"Capabilities:",
|
|
672
|
-
`- Interaction Contract: ${publicCapabilityStatus(capabilityState?.interactionContract)}`,
|
|
673
|
-
`- Skills: ${publicCapabilityStatus(capabilityState?.skills)}`,
|
|
674
561
|
`- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
|
|
675
562
|
`- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
|
|
676
|
-
`- Cognitive Routing: ${
|
|
563
|
+
`- Cognitive Routing: ${publicCognitiveRoutingStatus(capabilityState?.cognitiveRouting, cognitiveRoutingRuntime)}`,
|
|
677
564
|
"",
|
|
678
565
|
"Cognitive Routing:",
|
|
679
566
|
`- Control: \`${control}\``,
|
|
@@ -690,31 +577,68 @@ export function withoutFreeflowRuntimeState(messages) {
|
|
|
690
577
|
message?.customType !== COGNITIVE_ROUTING_RUNTIME_STATE_MESSAGE_TYPE,
|
|
691
578
|
);
|
|
692
579
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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);
|
|
698
616
|
}
|
|
699
617
|
export function runtimeContext(freeflowContext, capabilityState) {
|
|
700
|
-
if (
|
|
618
|
+
if (
|
|
619
|
+
capabilityState?.configured !== true ||
|
|
620
|
+
capabilityState?.enabled !== true ||
|
|
621
|
+
!hasUsableMandatoryPrompts(freeflowContext)
|
|
622
|
+
) {
|
|
701
623
|
return "";
|
|
702
624
|
}
|
|
703
|
-
const blocks = [];
|
|
704
|
-
if (
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
if (capabilityState.skills?.effective === true && freeflowContext?.skillsPrompt) {
|
|
709
|
-
blocks.push(freeflowContext.skillsPrompt.trim());
|
|
710
|
-
}
|
|
711
|
-
if (capabilityState.cognitiveRouting?.effective === true && freeflowContext?.cognitiveRoutingPrompt) {
|
|
625
|
+
const blocks = [freeflowContext.corePrompt.trim(), freeflowContext.interactionContractPrompt.trim()];
|
|
626
|
+
if (
|
|
627
|
+
capabilityState.cognitiveRouting?.effective === true &&
|
|
628
|
+
isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)
|
|
629
|
+
) {
|
|
712
630
|
blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
|
|
713
631
|
}
|
|
714
|
-
if (
|
|
632
|
+
if (
|
|
633
|
+
capabilityState.contextVirtualization?.effective === true &&
|
|
634
|
+
isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
|
|
635
|
+
) {
|
|
715
636
|
blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
|
|
716
637
|
}
|
|
717
|
-
if (
|
|
638
|
+
if (
|
|
639
|
+
capabilityState.conversationHistory?.effective === true &&
|
|
640
|
+
isPromptAvailable(freeflowContext.conversationHistoryPrompt)
|
|
641
|
+
) {
|
|
718
642
|
blocks.push(freeflowContext.conversationHistoryPrompt.trim());
|
|
719
643
|
}
|
|
720
644
|
return blocks.filter(Boolean).join("\n\n");
|
|
@@ -740,106 +664,22 @@ export async function setSessionCoreOverride(key, value, ctx, pi) {
|
|
|
740
664
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: { ...currentSessionOverrides } });
|
|
741
665
|
return {
|
|
742
666
|
changed: true,
|
|
743
|
-
reloadRequired: key === "enabled"
|
|
667
|
+
reloadRequired: key === "enabled",
|
|
744
668
|
sessionOverrides: { ...currentSessionOverrides },
|
|
745
669
|
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
746
670
|
};
|
|
747
671
|
}
|
|
748
672
|
export async function resetSessionOverrides(ctx, pi) {
|
|
749
673
|
const hadCoreOverrides = Object.keys(currentSessionOverrides).length > 0;
|
|
750
|
-
const reloadRequired =
|
|
751
|
-
Object.hasOwn(currentSessionOverrides, "enabled") || Object.hasOwn(currentSessionOverrides, "skillsEnabled");
|
|
752
|
-
const hadModeOverride = VALID_MODES.has(currentModeOverride);
|
|
674
|
+
const reloadRequired = Object.hasOwn(currentSessionOverrides, "enabled");
|
|
753
675
|
if (hadCoreOverrides) {
|
|
754
676
|
currentSessionOverrides = {};
|
|
755
677
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: {} });
|
|
756
678
|
}
|
|
757
|
-
if (hadModeOverride) {
|
|
758
|
-
await setSessionMode(null, ctx, pi);
|
|
759
|
-
}
|
|
760
679
|
return {
|
|
761
|
-
changed: hadCoreOverrides
|
|
680
|
+
changed: hadCoreOverrides,
|
|
762
681
|
reloadRequired,
|
|
763
682
|
sessionOverrides: { ...currentSessionOverrides },
|
|
764
|
-
|
|
683
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
765
684
|
};
|
|
766
685
|
}
|
|
767
|
-
export async function setSessionMode(mode, ctx, pi) {
|
|
768
|
-
const nextMode = mode === "default" || mode === "reset" || mode === null ? null : mode;
|
|
769
|
-
if (nextMode !== null && !VALID_MODES.has(nextMode)) {
|
|
770
|
-
throw new Error(`Invalid Freeflow mode: ${String(mode)}`);
|
|
771
|
-
}
|
|
772
|
-
currentModeOverride = nextMode;
|
|
773
|
-
pi?.appendEntry?.(MODE_STATE_ENTRY, { currentMode: nextMode });
|
|
774
|
-
return readModeState(ctx.cwd);
|
|
775
|
-
}
|
|
776
|
-
export async function handleModeCommand(args, ctx, pi) {
|
|
777
|
-
const arg = args?.trim();
|
|
778
|
-
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
779
|
-
const inactiveModeState = await readModeState(ctx.cwd);
|
|
780
|
-
if (!capabilityState.configured) {
|
|
781
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
782
|
-
ctx.ui.notify(
|
|
783
|
-
"Freeflow is installed but this repo is not set up. Run /setup-freeflow before changing mode.",
|
|
784
|
-
"warning",
|
|
785
|
-
);
|
|
786
|
-
return { changed: false, error: "not_configured" };
|
|
787
|
-
}
|
|
788
|
-
if (!capabilityState.enabled) {
|
|
789
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
790
|
-
ctx.ui.notify(
|
|
791
|
-
"Freeflow is disabled for this repo. Use /freeflow enable or /freeflow settings to re-enable it.",
|
|
792
|
-
"warning",
|
|
793
|
-
);
|
|
794
|
-
return { changed: false, error: "freeflow_disabled" };
|
|
795
|
-
}
|
|
796
|
-
if (!capabilityState.skills.effective) {
|
|
797
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
798
|
-
ctx.ui.notify(
|
|
799
|
-
`Freeflow modes are inactive because Skills are disabled. Configured default mode: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). Enable Skills in /freeflow settings before changing mode.`,
|
|
800
|
-
"warning",
|
|
801
|
-
);
|
|
802
|
-
return { changed: false, error: "skills_disabled" };
|
|
803
|
-
}
|
|
804
|
-
if (VALID_MODES.has(arg)) {
|
|
805
|
-
if (inactiveModeState.effectiveMode === arg) {
|
|
806
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
807
|
-
const message = inactiveModeState.sessionMode
|
|
808
|
-
? `Freeflow is already in ${arg} mode for this Pi session. No session entry was added. Configured default remains ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}).`
|
|
809
|
-
: `Freeflow is already in ${arg} mode from the configured default (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override was created.`;
|
|
810
|
-
ctx.ui.notify(message, "info");
|
|
811
|
-
return { changed: false, modeState: inactiveModeState };
|
|
812
|
-
}
|
|
813
|
-
const modeState = await setSessionMode(arg, ctx, pi);
|
|
814
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
815
|
-
ctx.ui.notify(
|
|
816
|
-
`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)}).`,
|
|
817
|
-
"info",
|
|
818
|
-
);
|
|
819
|
-
return { changed: true, modeState };
|
|
820
|
-
}
|
|
821
|
-
if (RESET_MODE_ARGS.has(arg) || arg === "default") {
|
|
822
|
-
if (!inactiveModeState.sessionMode) {
|
|
823
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
824
|
-
ctx.ui.notify(
|
|
825
|
-
`Freeflow is already using the configured default: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override is active.`,
|
|
826
|
-
"info",
|
|
827
|
-
);
|
|
828
|
-
return { changed: false, modeState: inactiveModeState };
|
|
829
|
-
}
|
|
830
|
-
const modeState = await setSessionMode(null, ctx, pi);
|
|
831
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
832
|
-
ctx.ui.notify(
|
|
833
|
-
`Freeflow mode reset to configured default: ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)}). Session override cleared; .freeflow/local.json and .freeflow/config.json were not changed.`,
|
|
834
|
-
"info",
|
|
835
|
-
);
|
|
836
|
-
return { changed: true, modeState };
|
|
837
|
-
}
|
|
838
|
-
const modeState = await readModeState(ctx.cwd);
|
|
839
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
840
|
-
ctx.ui.notify(
|
|
841
|
-
`Freeflow mode is ${modeState.effectiveMode} (${describeModeState(modeState)}). Use /freeflow mode conversation, /freeflow mode workflow, /freeflow mode strict-workflow, or /freeflow mode reset.`,
|
|
842
|
-
"info",
|
|
843
|
-
);
|
|
844
|
-
return { changed: false, modeState, error: arg ? "invalid_mode" : undefined };
|
|
845
|
-
}
|