@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
|
@@ -3,9 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
5
|
import { resolveCognitiveRoutingState } from "../cognitive-routing/runtime.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export const VALID_MODES = new Set(["conversation", "workflow", "strict-workflow"]);
|
|
6
|
+
import { supportsCognitiveRoutingModelRegistry } from "../cognitive-routing/host.js";
|
|
9
7
|
|
|
10
8
|
export const WORKFLOW_COMMANDS = [
|
|
11
9
|
{ command: "discuss", skill: "discuss" },
|
|
@@ -43,7 +41,6 @@ export const FREEFLOW_MODEL_SKILL_NAMES = [
|
|
|
43
41
|
"execute-work",
|
|
44
42
|
"finish-branch",
|
|
45
43
|
"handoff",
|
|
46
|
-
"mode-contract",
|
|
47
44
|
"release-work",
|
|
48
45
|
"review-artifact",
|
|
49
46
|
"review-work",
|
|
@@ -84,20 +81,11 @@ export function freeflowModelSkillPaths(capabilityState = undefined) {
|
|
|
84
81
|
return paths;
|
|
85
82
|
}
|
|
86
83
|
|
|
87
|
-
type SessionCoreKey =
|
|
88
|
-
"enabled" | "interactionContract" | "skillsEnabled" | "contextVirtualization" | "conversationHistory";
|
|
84
|
+
type SessionCoreKey = "enabled" | "contextVirtualization" | "conversationHistory";
|
|
89
85
|
type SessionCoreOverrides = Partial<Record<SessionCoreKey, boolean>>;
|
|
90
86
|
|
|
91
|
-
const MODE_STATE_ENTRY = "freeflow-mode";
|
|
92
87
|
const SESSION_OVERRIDES_ENTRY = "freeflow-session-overrides";
|
|
93
|
-
const SESSION_CORE_KEYS = new Set<SessionCoreKey>([
|
|
94
|
-
"enabled",
|
|
95
|
-
"interactionContract",
|
|
96
|
-
"skillsEnabled",
|
|
97
|
-
"contextVirtualization",
|
|
98
|
-
"conversationHistory",
|
|
99
|
-
]);
|
|
100
|
-
const RESET_MODE_ARGS = new Set(["reset"]);
|
|
88
|
+
const SESSION_CORE_KEYS = new Set<SessionCoreKey>(["enabled", "contextVirtualization", "conversationHistory"]);
|
|
101
89
|
|
|
102
90
|
export const COGNITIVE_ROUTING_SWITCH_TOOL_NAME = "freeflow_switch_profile";
|
|
103
91
|
export const FREEFLOW_RUNTIME_STATE_MESSAGE_TYPE = "freeflow-runtime-state";
|
|
@@ -107,12 +95,22 @@ export const COGNITIVE_ROUTING_BOOTSTRAP_MESSAGE_TYPE = "freeflow-cognitive-rout
|
|
|
107
95
|
export const FREEFLOW_BOOTSTRAP_MESSAGE_TYPE = "freeflow-bootstrap";
|
|
108
96
|
|
|
109
97
|
let runtimeContextCache = null;
|
|
110
|
-
let currentModeOverride = null;
|
|
111
98
|
let currentSessionOverrides: SessionCoreOverrides = {};
|
|
112
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
|
+
|
|
113
110
|
async function readPromptFile(url: URL): Promise<string | null> {
|
|
114
111
|
try {
|
|
115
|
-
|
|
112
|
+
const prompt = await readFile(url, "utf8");
|
|
113
|
+
return isPromptAvailable(prompt) ? prompt.trim() : null;
|
|
116
114
|
} catch {
|
|
117
115
|
return null;
|
|
118
116
|
}
|
|
@@ -120,15 +118,12 @@ async function readPromptFile(url: URL): Promise<string | null> {
|
|
|
120
118
|
|
|
121
119
|
async function loadRuntimeContext(capabilityState = undefined) {
|
|
122
120
|
const freeflowEnabled = capabilityState?.enabled === true;
|
|
123
|
-
const interactionContractEnabled = capabilityState?.interactionContract?.effective === true;
|
|
124
|
-
const skillsEnabled = capabilityState?.skills?.effective === true;
|
|
125
121
|
const contextVirtualizationEnabled = capabilityState?.contextVirtualization?.effective === true;
|
|
126
122
|
const conversationHistoryEnabled = capabilityState?.conversationHistory?.effective === true;
|
|
127
123
|
const cognitiveRoutingEnabled = capabilityState?.cognitiveRouting?.effective === true;
|
|
128
124
|
const [
|
|
129
125
|
corePrompt,
|
|
130
126
|
interactionContractPrompt,
|
|
131
|
-
skillsPrompt,
|
|
132
127
|
cognitiveRoutingPrompt,
|
|
133
128
|
contextVirtualizationPrompt,
|
|
134
129
|
conversationHistoryPrompt,
|
|
@@ -136,12 +131,9 @@ async function loadRuntimeContext(capabilityState = undefined) {
|
|
|
136
131
|
freeflowEnabled
|
|
137
132
|
? readPromptFile(new URL("../../../runtime/prompts/core.md", import.meta.url))
|
|
138
133
|
: Promise.resolve(null),
|
|
139
|
-
|
|
134
|
+
freeflowEnabled
|
|
140
135
|
? readPromptFile(new URL("../../../runtime/prompts/interaction-contract.md", import.meta.url))
|
|
141
136
|
: Promise.resolve(null),
|
|
142
|
-
skillsEnabled
|
|
143
|
-
? readPromptFile(new URL("../../../runtime/prompts/skills.md", import.meta.url))
|
|
144
|
-
: Promise.resolve(null),
|
|
145
137
|
cognitiveRoutingEnabled
|
|
146
138
|
? readPromptFile(new URL("../../../runtime/prompts/cognitive-routing.md", import.meta.url))
|
|
147
139
|
: Promise.resolve(null),
|
|
@@ -156,7 +148,6 @@ async function loadRuntimeContext(capabilityState = undefined) {
|
|
|
156
148
|
return {
|
|
157
149
|
corePrompt,
|
|
158
150
|
interactionContractPrompt,
|
|
159
|
-
skillsPrompt,
|
|
160
151
|
cognitiveRoutingPrompt,
|
|
161
152
|
contextVirtualizationPrompt,
|
|
162
153
|
conversationHistoryPrompt,
|
|
@@ -167,13 +158,12 @@ function runtimeContextCacheSatisfies(capabilityState) {
|
|
|
167
158
|
if (!runtimeContextCache) return false;
|
|
168
159
|
const expected = {
|
|
169
160
|
corePrompt: capabilityState?.enabled === true,
|
|
170
|
-
interactionContractPrompt: capabilityState?.
|
|
171
|
-
skillsPrompt: capabilityState?.skills?.effective === true,
|
|
161
|
+
interactionContractPrompt: capabilityState?.enabled === true,
|
|
172
162
|
cognitiveRoutingPrompt: capabilityState?.cognitiveRouting?.effective === true,
|
|
173
163
|
contextVirtualizationPrompt: capabilityState?.contextVirtualization?.effective === true,
|
|
174
164
|
conversationHistoryPrompt: capabilityState?.conversationHistory?.effective === true,
|
|
175
165
|
};
|
|
176
|
-
return Object.entries(expected).every(([key, required]) => !required ||
|
|
166
|
+
return Object.entries(expected).every(([key, required]) => !required || isPromptAvailable(runtimeContextCache[key]));
|
|
177
167
|
}
|
|
178
168
|
|
|
179
169
|
export async function refreshRuntimeContext(capabilityState = undefined) {
|
|
@@ -223,10 +213,6 @@ function isRecord(value) {
|
|
|
223
213
|
}
|
|
224
214
|
|
|
225
215
|
function validateCoreConfigFields(value) {
|
|
226
|
-
if (value.defaultMode !== undefined && !VALID_MODES.has(value.defaultMode)) {
|
|
227
|
-
return `invalid defaultMode: ${JSON.stringify(value.defaultMode)}`;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
216
|
if (value.enabled !== undefined && typeof value.enabled !== "boolean") {
|
|
231
217
|
return "enabled must be a boolean";
|
|
232
218
|
}
|
|
@@ -239,24 +225,6 @@ function validateCoreConfigFields(value) {
|
|
|
239
225
|
return "conversationHistory must be a boolean";
|
|
240
226
|
}
|
|
241
227
|
|
|
242
|
-
if (value.interactionContract !== undefined && typeof value.interactionContract !== "boolean") {
|
|
243
|
-
return "interactionContract must be a boolean";
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (value.skills !== undefined) {
|
|
247
|
-
if (!isRecord(value.skills)) {
|
|
248
|
-
return "skills must be an object";
|
|
249
|
-
}
|
|
250
|
-
for (const key of Object.keys(value.skills)) {
|
|
251
|
-
if (key !== "enabled") {
|
|
252
|
-
return `unsupported skills config key: ${key}`;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (value.skills.enabled !== undefined && typeof value.skills.enabled !== "boolean") {
|
|
256
|
-
return "skills.enabled must be a boolean";
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
228
|
return null;
|
|
261
229
|
}
|
|
262
230
|
|
|
@@ -268,9 +236,6 @@ function validateFreeflowConfigShape(value) {
|
|
|
268
236
|
// Keep retired capability keys shape-tolerated so existing repositories remain activated; runtime behavior ignores them.
|
|
269
237
|
const allowedKeys = new Set([
|
|
270
238
|
"enabled",
|
|
271
|
-
"defaultMode",
|
|
272
|
-
"interactionContract",
|
|
273
|
-
"skills",
|
|
274
239
|
"outputRouter",
|
|
275
240
|
"observedRouting",
|
|
276
241
|
"scriptTransform",
|
|
@@ -303,9 +268,6 @@ function validateFreeflowLocalConfigShape(value) {
|
|
|
303
268
|
|
|
304
269
|
const allowedKeys = new Set([
|
|
305
270
|
"enabled",
|
|
306
|
-
"defaultMode",
|
|
307
|
-
"interactionContract",
|
|
308
|
-
"skills",
|
|
309
271
|
"processing",
|
|
310
272
|
"cognitiveRouting",
|
|
311
273
|
"contextVirtualization",
|
|
@@ -387,30 +349,19 @@ function resolveLayeredValue(repository, local, key, fallback) {
|
|
|
387
349
|
|
|
388
350
|
function resolveCoreConfig(repository, local) {
|
|
389
351
|
const enabled = resolveLayeredValue(repository, local, "enabled", true);
|
|
390
|
-
const interactionContract = resolveLayeredValue(repository, local, "interactionContract", true);
|
|
391
352
|
const contextVirtualization = resolveLayeredValue(repository, local, "contextVirtualization", false);
|
|
392
353
|
const conversationHistory = resolveLayeredValue(repository, local, "conversationHistory", false);
|
|
393
|
-
const defaultMode = resolveLayeredValue(repository, local, "defaultMode", "workflow");
|
|
394
|
-
const repositorySkills = isRecord(repository.skills) ? repository.skills : {};
|
|
395
|
-
const localSkills = isRecord(local.skills) ? local.skills : {};
|
|
396
|
-
const skillsEnabled = resolveLayeredValue(repositorySkills, localSkills, "enabled", true);
|
|
397
354
|
|
|
398
355
|
return {
|
|
399
356
|
config: {
|
|
400
357
|
enabled: enabled.value,
|
|
401
|
-
interactionContract: interactionContract.value,
|
|
402
358
|
contextVirtualization: contextVirtualization.value,
|
|
403
359
|
conversationHistory: conversationHistory.value,
|
|
404
|
-
skills: { enabled: skillsEnabled.value },
|
|
405
|
-
defaultMode: defaultMode.value,
|
|
406
360
|
},
|
|
407
361
|
sources: {
|
|
408
362
|
enabled: enabled.source,
|
|
409
|
-
interactionContract: interactionContract.source,
|
|
410
363
|
contextVirtualization: contextVirtualization.source,
|
|
411
364
|
conversationHistory: conversationHistory.source,
|
|
412
|
-
skillsEnabled: skillsEnabled.source,
|
|
413
|
-
defaultMode: defaultMode.source,
|
|
414
365
|
},
|
|
415
366
|
};
|
|
416
367
|
}
|
|
@@ -430,30 +381,21 @@ function resolveSessionCoreConfig(layers) {
|
|
|
430
381
|
const configured = layers.coreConfig;
|
|
431
382
|
const sources = layers.sources;
|
|
432
383
|
const enabled = currentSessionOverrides.enabled;
|
|
433
|
-
const interactionContract = currentSessionOverrides.interactionContract;
|
|
434
384
|
const contextVirtualization = currentSessionOverrides.contextVirtualization;
|
|
435
385
|
const conversationHistory = currentSessionOverrides.conversationHistory;
|
|
436
|
-
const skillsEnabled = currentSessionOverrides.skillsEnabled;
|
|
437
386
|
|
|
438
387
|
return {
|
|
439
388
|
config: {
|
|
440
389
|
enabled: typeof enabled === "boolean" ? enabled : configured.enabled,
|
|
441
|
-
interactionContract:
|
|
442
|
-
typeof interactionContract === "boolean" ? interactionContract : configured.interactionContract,
|
|
443
390
|
contextVirtualization:
|
|
444
391
|
typeof contextVirtualization === "boolean" ? contextVirtualization : configured.contextVirtualization,
|
|
445
392
|
conversationHistory:
|
|
446
393
|
typeof conversationHistory === "boolean" ? conversationHistory : configured.conversationHistory,
|
|
447
|
-
skills: { enabled: typeof skillsEnabled === "boolean" ? skillsEnabled : configured.skills.enabled },
|
|
448
|
-
defaultMode: configured.defaultMode,
|
|
449
394
|
},
|
|
450
395
|
sources: {
|
|
451
396
|
enabled: typeof enabled === "boolean" ? "session" : sources.enabled,
|
|
452
|
-
interactionContract: typeof interactionContract === "boolean" ? "session" : sources.interactionContract,
|
|
453
397
|
contextVirtualization: typeof contextVirtualization === "boolean" ? "session" : sources.contextVirtualization,
|
|
454
398
|
conversationHistory: typeof conversationHistory === "boolean" ? "session" : sources.conversationHistory,
|
|
455
|
-
skillsEnabled: typeof skillsEnabled === "boolean" ? "session" : sources.skillsEnabled,
|
|
456
|
-
defaultMode: sources.defaultMode,
|
|
457
399
|
},
|
|
458
400
|
};
|
|
459
401
|
}
|
|
@@ -488,55 +430,27 @@ export async function readCapabilityState(cwd, host = undefined, extensionHost =
|
|
|
488
430
|
const layers = await readFreeflowConfigLayers(cwd);
|
|
489
431
|
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
490
432
|
const enabled = layers.configured && effectiveCore.config.enabled;
|
|
491
|
-
const interactionContractConfigEnabled = effectiveCore.config.interactionContract;
|
|
492
|
-
const skillsConfigEnabled = effectiveCore.config.skills.enabled;
|
|
493
433
|
const contextVirtualizationConfigEnabled = effectiveCore.config.contextVirtualization;
|
|
494
434
|
const conversationHistoryConfigEnabled = effectiveCore.config.conversationHistory;
|
|
495
|
-
const
|
|
496
|
-
const hostSupportsCognitiveRouting = isPiFlowHost(extensionHost);
|
|
435
|
+
const hostSupportsCognitiveRouting = supportsCognitiveRoutingModelRegistry(host);
|
|
497
436
|
const configuredCognitiveRouting = await resolveCognitiveRoutingState(
|
|
498
437
|
layers.repository.parsed,
|
|
499
438
|
layers.local.parsed,
|
|
500
439
|
hostSupportsCognitiveRouting ? host : undefined,
|
|
501
440
|
);
|
|
502
|
-
const disabledReason = enabled
|
|
503
|
-
? skillsEffective
|
|
504
|
-
? undefined
|
|
505
|
-
: { code: "disabled" as const, message: "Skills are disabled" }
|
|
506
|
-
: { code: "disabled" as const, message: "Freeflow is disabled" };
|
|
441
|
+
const disabledReason = enabled ? undefined : { code: "disabled" as const, message: "Freeflow is disabled" };
|
|
507
442
|
const childCapability = (configuredEnabled) => ({
|
|
508
443
|
enabled: configuredEnabled,
|
|
509
|
-
effective:
|
|
444
|
+
effective: enabled && configuredEnabled,
|
|
510
445
|
...(disabledReason ? { blockingReason: disabledReason } : {}),
|
|
511
446
|
});
|
|
512
447
|
const cognitiveRouting = enabled
|
|
513
|
-
?
|
|
514
|
-
? !hostSupportsCognitiveRouting && configuredCognitiveRouting.configValid
|
|
515
|
-
? {
|
|
516
|
-
...configuredCognitiveRouting,
|
|
517
|
-
effective: false,
|
|
518
|
-
blockingReason: {
|
|
519
|
-
code: "runtime_disabled" as const,
|
|
520
|
-
message: "Cognitive Routing is disabled outside the PiFlow runtime",
|
|
521
|
-
},
|
|
522
|
-
}
|
|
523
|
-
: configuredCognitiveRouting
|
|
524
|
-
: {
|
|
525
|
-
...configuredCognitiveRouting,
|
|
526
|
-
effective: false,
|
|
527
|
-
blockingReason: {
|
|
528
|
-
code: "disabled" as const,
|
|
529
|
-
message: "Skills are disabled",
|
|
530
|
-
},
|
|
531
|
-
}
|
|
448
|
+
? configuredCognitiveRouting
|
|
532
449
|
: {
|
|
533
450
|
...configuredCognitiveRouting,
|
|
534
451
|
enabled: false,
|
|
535
452
|
effective: false,
|
|
536
|
-
blockingReason:
|
|
537
|
-
code: "disabled" as const,
|
|
538
|
-
message: "Freeflow is disabled",
|
|
539
|
-
},
|
|
453
|
+
blockingReason: disabledReason,
|
|
540
454
|
};
|
|
541
455
|
return {
|
|
542
456
|
configured: layers.configured,
|
|
@@ -553,16 +467,7 @@ export async function readCapabilityState(cwd, host = undefined, extensionHost =
|
|
|
553
467
|
configuredSources: layers.sources,
|
|
554
468
|
sessionOverrides: { ...currentSessionOverrides },
|
|
555
469
|
configSources: effectiveCore.sources,
|
|
556
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
557
470
|
enabled,
|
|
558
|
-
interactionContract: {
|
|
559
|
-
enabled: interactionContractConfigEnabled,
|
|
560
|
-
effective: enabled && interactionContractConfigEnabled,
|
|
561
|
-
},
|
|
562
|
-
skills: {
|
|
563
|
-
enabled: skillsConfigEnabled,
|
|
564
|
-
effective: enabled && skillsConfigEnabled,
|
|
565
|
-
},
|
|
566
471
|
contextVirtualization: childCapability(contextVirtualizationConfigEnabled),
|
|
567
472
|
conversationHistory: childCapability(conversationHistoryConfigEnabled),
|
|
568
473
|
hostSupportsCognitiveRouting,
|
|
@@ -572,53 +477,23 @@ export async function readCapabilityState(cwd, host = undefined, extensionHost =
|
|
|
572
477
|
|
|
573
478
|
export const readRuntimeState = readCapabilityState;
|
|
574
479
|
|
|
575
|
-
export function
|
|
576
|
-
currentModeOverride = null;
|
|
480
|
+
export function restoreSessionOverrides(ctx) {
|
|
577
481
|
currentSessionOverrides = {};
|
|
578
482
|
const entries = ctx.sessionManager?.getBranch?.() ?? ctx.sessionManager?.getEntries?.() ?? [];
|
|
579
483
|
|
|
580
484
|
for (const entry of entries) {
|
|
581
|
-
if (entry.type
|
|
582
|
-
if (entry.customType === MODE_STATE_ENTRY) {
|
|
583
|
-
const mode = entry.data?.currentMode;
|
|
584
|
-
currentModeOverride = VALID_MODES.has(mode) ? mode : null;
|
|
585
|
-
} else if (entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
485
|
+
if (entry.type === "custom" && entry.customType === SESSION_OVERRIDES_ENTRY) {
|
|
586
486
|
currentSessionOverrides = normalizeSessionOverrides(entry.data?.overrides);
|
|
587
487
|
}
|
|
588
488
|
}
|
|
589
489
|
}
|
|
590
490
|
|
|
591
|
-
export
|
|
592
|
-
const layers = await readFreeflowConfigLayers(cwd);
|
|
593
|
-
const effectiveCore = resolveSessionCoreConfig(layers);
|
|
594
|
-
const repositoryDefaultMode = VALID_MODES.has(layers.repository.parsed.defaultMode)
|
|
595
|
-
? layers.repository.parsed.defaultMode
|
|
596
|
-
: "workflow";
|
|
597
|
-
const personalDefaultMode = VALID_MODES.has(layers.local.parsed.defaultMode) ? layers.local.parsed.defaultMode : null;
|
|
598
|
-
const sessionMode = VALID_MODES.has(currentModeOverride) ? currentModeOverride : null;
|
|
599
|
-
const resolvedMode = sessionMode ?? effectiveCore.config.defaultMode;
|
|
600
|
-
const active = layers.configured && effectiveCore.config.enabled && effectiveCore.config.skills.enabled;
|
|
601
|
-
|
|
602
|
-
return {
|
|
603
|
-
repositoryDefaultMode,
|
|
604
|
-
repositoryDefaultModeSource: VALID_MODES.has(layers.repository.parsed.defaultMode) ? "repository" : "builtin",
|
|
605
|
-
personalDefaultMode,
|
|
606
|
-
defaultMode: effectiveCore.config.defaultMode,
|
|
607
|
-
defaultModeSource: effectiveCore.sources.defaultMode,
|
|
608
|
-
currentMode: sessionMode,
|
|
609
|
-
sessionMode,
|
|
610
|
-
resolvedMode,
|
|
611
|
-
active,
|
|
612
|
-
effectiveMode: active ? resolvedMode : null,
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
export function setModeStatus(
|
|
491
|
+
export function setFreeflowStatus(
|
|
617
492
|
ctx,
|
|
618
|
-
modeState,
|
|
619
493
|
capabilityState = undefined,
|
|
620
494
|
cognitiveRoutingRuntime = undefined,
|
|
621
|
-
|
|
495
|
+
freeflowContext = undefined,
|
|
496
|
+
options: { cognitiveRoutingStartupPending?: boolean; startupSelectionSuppressed?: boolean } = {},
|
|
622
497
|
) {
|
|
623
498
|
if (capabilityState && !capabilityState.configured) {
|
|
624
499
|
ctx.ui.setStatus("freeflow", capabilityState.configExists ? "freeflow: config error" : "freeflow: setup needed");
|
|
@@ -629,23 +504,26 @@ export function setModeStatus(
|
|
|
629
504
|
ctx.ui.setStatus("freeflow", `freeflow: off${source}`);
|
|
630
505
|
return;
|
|
631
506
|
}
|
|
507
|
+
if (capabilityState?.enabled === true && !hasUsableMandatoryPrompts(freeflowContext)) {
|
|
508
|
+
ctx.ui.setStatus("freeflow", "freeflow: unavailable");
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
632
511
|
|
|
633
512
|
const active: string[] = [];
|
|
634
|
-
if (capabilityState?.interactionContract.effective) {
|
|
635
|
-
active.push("interaction");
|
|
636
|
-
} else if (capabilityState?.configSources?.interactionContract === "session") {
|
|
637
|
-
active.push("interaction off (session)");
|
|
638
|
-
}
|
|
639
|
-
if (capabilityState?.skills.effective) {
|
|
640
|
-
active.push(`${modeState.effectiveMode}${modeState.currentMode ? " (session)" : ""}`);
|
|
641
|
-
} else if (capabilityState?.configSources?.skillsEnabled === "session") {
|
|
642
|
-
active.push("skills off (session)");
|
|
643
|
-
}
|
|
644
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");
|
|
645
520
|
const cognitiveRoutingActive = cognitiveRouting?.effective === true && cognitiveRoutingRuntime?.effective === true;
|
|
646
|
-
const startupSelectionSuppressesCognitiveRouting =
|
|
647
|
-
|
|
648
|
-
|
|
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) {
|
|
649
527
|
const profile = cognitiveRoutingRuntime.activeProfile;
|
|
650
528
|
const control =
|
|
651
529
|
cognitiveRoutingRuntime.controlMode === "manual-standard" ||
|
|
@@ -655,18 +533,21 @@ export function setModeStatus(
|
|
|
655
533
|
active.push(`${profile} · ${control}`);
|
|
656
534
|
} else if (cognitiveRouting?.enabled === true) {
|
|
657
535
|
if (cognitiveRouting.blockingReason?.code === "runtime_disabled") {
|
|
658
|
-
active.push("cognitive
|
|
536
|
+
active.push("cognitive blocked · runtime_disabled");
|
|
659
537
|
} else if (
|
|
660
538
|
cognitiveRouting.effective === true &&
|
|
661
539
|
cognitiveRoutingRuntime === undefined &&
|
|
662
540
|
options.cognitiveRoutingStartupPending === true &&
|
|
663
541
|
!startupSelectionSuppressesCognitiveRouting
|
|
664
542
|
) {
|
|
665
|
-
const startupProfile =
|
|
543
|
+
const startupProfile =
|
|
544
|
+
cognitiveRouting.sessionStart?.control === "manual"
|
|
545
|
+
? (cognitiveRouting.sessionStart.profile ?? "reasoning")
|
|
546
|
+
: "reasoning";
|
|
666
547
|
active.push(`${startupProfile} · pending`);
|
|
667
548
|
} else {
|
|
668
549
|
const reason =
|
|
669
|
-
cognitiveRouting
|
|
550
|
+
cognitiveRouting.effective === true
|
|
670
551
|
? (cognitiveRoutingRuntime?.blockingReason?.code ?? "runtime_inactive")
|
|
671
552
|
: (cognitiveRouting.blockingReason?.code ?? "unavailable");
|
|
672
553
|
active.push(`cognitive blocked · ${reason}`);
|
|
@@ -675,21 +556,7 @@ export function setModeStatus(
|
|
|
675
556
|
if (capabilityState?.contextVirtualization?.effective || capabilityState?.conversationHistory?.effective) {
|
|
676
557
|
active.push("context");
|
|
677
558
|
}
|
|
678
|
-
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
function modeSourceLabel(source) {
|
|
682
|
-
if (source === "local") return "personal override";
|
|
683
|
-
if (source === "repository") return "repository default";
|
|
684
|
-
return "built-in default";
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
function describeModeState(modeState) {
|
|
688
|
-
const configuredDefault = `configured default ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)})`;
|
|
689
|
-
if (modeState.sessionMode) {
|
|
690
|
-
return `session ${modeState.sessionMode}; ${configuredDefault}`;
|
|
691
|
-
}
|
|
692
|
-
return configuredDefault;
|
|
559
|
+
ctx.ui.setStatus("freeflow", `freeflow: ${active.length > 0 ? active.join(" · ") : "active"}`);
|
|
693
560
|
}
|
|
694
561
|
|
|
695
562
|
export function skillPrompt(skill, args) {
|
|
@@ -699,6 +566,8 @@ export function skillPrompt(skill, args) {
|
|
|
699
566
|
|
|
700
567
|
type CognitiveRoutingRuntimeSnapshot = {
|
|
701
568
|
effective?: boolean;
|
|
569
|
+
runtimeStatus?: "active" | "inactive" | "blocked";
|
|
570
|
+
runtimeReason?: unknown;
|
|
702
571
|
activeProfile?: unknown;
|
|
703
572
|
controlMode?: unknown;
|
|
704
573
|
};
|
|
@@ -727,10 +596,15 @@ function publicCapabilityStatus(capability) {
|
|
|
727
596
|
return "inactive";
|
|
728
597
|
}
|
|
729
598
|
|
|
599
|
+
function publicCognitiveRoutingStatus(capability, runtime) {
|
|
600
|
+
if (runtime?.runtimeStatus === "inactive") return "inactive";
|
|
601
|
+
return publicCapabilityStatus(capability);
|
|
602
|
+
}
|
|
603
|
+
|
|
730
604
|
export function freeflowRuntimeStateMessage(
|
|
731
|
-
modeState,
|
|
732
605
|
capabilityState,
|
|
733
606
|
cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
|
|
607
|
+
freeflowContext = undefined,
|
|
734
608
|
) {
|
|
735
609
|
const cognitiveRoutingEffective = capabilityState?.cognitiveRouting?.effective === true;
|
|
736
610
|
const profile = publicCognitiveRoutingProfile(
|
|
@@ -739,8 +613,16 @@ export function freeflowRuntimeStateMessage(
|
|
|
739
613
|
);
|
|
740
614
|
const control =
|
|
741
615
|
profile === "unavailable" ? "unavailable" : publicCognitiveRoutingControl(cognitiveRoutingRuntime?.controlMode);
|
|
742
|
-
const
|
|
743
|
-
const
|
|
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";
|
|
744
626
|
|
|
745
627
|
return {
|
|
746
628
|
role: "custom",
|
|
@@ -750,15 +632,12 @@ export function freeflowRuntimeStateMessage(
|
|
|
750
632
|
"",
|
|
751
633
|
"This is extension-generated runtime state. Use it to interpret the stable Freeflow guidance.",
|
|
752
634
|
"",
|
|
753
|
-
`
|
|
754
|
-
`Active mode: \`${activeMode}\``,
|
|
635
|
+
`Freeflow: ${freeflowStatus}`,
|
|
755
636
|
"",
|
|
756
637
|
"Capabilities:",
|
|
757
|
-
`- Interaction Contract: ${publicCapabilityStatus(capabilityState?.interactionContract)}`,
|
|
758
|
-
`- Skills: ${publicCapabilityStatus(capabilityState?.skills)}`,
|
|
759
638
|
`- Context Virtualization: ${publicCapabilityStatus(capabilityState?.contextVirtualization)}`,
|
|
760
639
|
`- Conversation History: ${publicCapabilityStatus(capabilityState?.conversationHistory)}`,
|
|
761
|
-
`- Cognitive Routing: ${
|
|
640
|
+
`- Cognitive Routing: ${publicCognitiveRoutingStatus(capabilityState?.cognitiveRouting, cognitiveRoutingRuntime)}`,
|
|
762
641
|
"",
|
|
763
642
|
"Cognitive Routing:",
|
|
764
643
|
`- Control: \`${control}\``,
|
|
@@ -777,38 +656,75 @@ export function withoutFreeflowRuntimeState(messages: readonly FreeflowContextMe
|
|
|
777
656
|
);
|
|
778
657
|
}
|
|
779
658
|
|
|
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
|
+
}
|
|
665
|
+
|
|
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)];
|
|
673
|
+
}
|
|
674
|
+
|
|
780
675
|
export function withFreeflowRuntimeState(
|
|
781
676
|
messages: readonly FreeflowContextMessage[] | undefined,
|
|
782
|
-
modeState,
|
|
783
677
|
capabilityState,
|
|
784
678
|
cognitiveRoutingRuntime: CognitiveRoutingRuntimeSnapshot | undefined = undefined,
|
|
679
|
+
freeflowContext = undefined,
|
|
680
|
+
options: { force?: boolean } = {},
|
|
785
681
|
) {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
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);
|
|
790
700
|
}
|
|
791
701
|
|
|
792
702
|
export function runtimeContext(freeflowContext, capabilityState) {
|
|
793
|
-
if (
|
|
703
|
+
if (
|
|
704
|
+
capabilityState?.configured !== true ||
|
|
705
|
+
capabilityState?.enabled !== true ||
|
|
706
|
+
!hasUsableMandatoryPrompts(freeflowContext)
|
|
707
|
+
) {
|
|
794
708
|
return "";
|
|
795
709
|
}
|
|
796
710
|
|
|
797
|
-
const blocks = [];
|
|
798
|
-
if (
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (capabilityState.skills?.effective === true && freeflowContext?.skillsPrompt) {
|
|
803
|
-
blocks.push(freeflowContext.skillsPrompt.trim());
|
|
804
|
-
}
|
|
805
|
-
if (capabilityState.cognitiveRouting?.effective === true && freeflowContext?.cognitiveRoutingPrompt) {
|
|
711
|
+
const blocks = [freeflowContext.corePrompt.trim(), freeflowContext.interactionContractPrompt.trim()];
|
|
712
|
+
if (
|
|
713
|
+
capabilityState.cognitiveRouting?.effective === true &&
|
|
714
|
+
isPromptAvailable(freeflowContext.cognitiveRoutingPrompt)
|
|
715
|
+
) {
|
|
806
716
|
blocks.push(freeflowContext.cognitiveRoutingPrompt.trim());
|
|
807
717
|
}
|
|
808
|
-
if (
|
|
718
|
+
if (
|
|
719
|
+
capabilityState.contextVirtualization?.effective === true &&
|
|
720
|
+
isPromptAvailable(freeflowContext.contextVirtualizationPrompt)
|
|
721
|
+
) {
|
|
809
722
|
blocks.push(freeflowContext.contextVirtualizationPrompt.trim());
|
|
810
723
|
}
|
|
811
|
-
if (
|
|
724
|
+
if (
|
|
725
|
+
capabilityState.conversationHistory?.effective === true &&
|
|
726
|
+
isPromptAvailable(freeflowContext.conversationHistoryPrompt)
|
|
727
|
+
) {
|
|
812
728
|
blocks.push(freeflowContext.conversationHistoryPrompt.trim());
|
|
813
729
|
}
|
|
814
730
|
return blocks.filter(Boolean).join("\n\n");
|
|
@@ -837,7 +753,7 @@ export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean
|
|
|
837
753
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: { ...currentSessionOverrides } });
|
|
838
754
|
return {
|
|
839
755
|
changed: true,
|
|
840
|
-
reloadRequired: key === "enabled"
|
|
756
|
+
reloadRequired: key === "enabled",
|
|
841
757
|
sessionOverrides: { ...currentSessionOverrides },
|
|
842
758
|
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
843
759
|
};
|
|
@@ -845,109 +761,17 @@ export async function setSessionCoreOverride(key: SessionCoreKey, value: boolean
|
|
|
845
761
|
|
|
846
762
|
export async function resetSessionOverrides(ctx, pi) {
|
|
847
763
|
const hadCoreOverrides = Object.keys(currentSessionOverrides).length > 0;
|
|
848
|
-
const reloadRequired =
|
|
849
|
-
Object.hasOwn(currentSessionOverrides, "enabled") || Object.hasOwn(currentSessionOverrides, "skillsEnabled");
|
|
850
|
-
const hadModeOverride = VALID_MODES.has(currentModeOverride);
|
|
764
|
+
const reloadRequired = Object.hasOwn(currentSessionOverrides, "enabled");
|
|
851
765
|
|
|
852
766
|
if (hadCoreOverrides) {
|
|
853
767
|
currentSessionOverrides = {};
|
|
854
768
|
pi?.appendEntry?.(SESSION_OVERRIDES_ENTRY, { overrides: {} });
|
|
855
769
|
}
|
|
856
|
-
if (hadModeOverride) {
|
|
857
|
-
await setSessionMode(null, ctx, pi);
|
|
858
|
-
}
|
|
859
770
|
|
|
860
771
|
return {
|
|
861
|
-
changed: hadCoreOverrides
|
|
772
|
+
changed: hadCoreOverrides,
|
|
862
773
|
reloadRequired,
|
|
863
774
|
sessionOverrides: { ...currentSessionOverrides },
|
|
864
|
-
|
|
775
|
+
capabilityState: await readCapabilityState(ctx.cwd, ctx, pi?.host),
|
|
865
776
|
};
|
|
866
777
|
}
|
|
867
|
-
|
|
868
|
-
export async function setSessionMode(mode, ctx, pi) {
|
|
869
|
-
const nextMode = mode === "default" || mode === "reset" || mode === null ? null : mode;
|
|
870
|
-
if (nextMode !== null && !VALID_MODES.has(nextMode)) {
|
|
871
|
-
throw new Error(`Invalid Freeflow mode: ${String(mode)}`);
|
|
872
|
-
}
|
|
873
|
-
currentModeOverride = nextMode;
|
|
874
|
-
pi?.appendEntry?.(MODE_STATE_ENTRY, { currentMode: nextMode });
|
|
875
|
-
return readModeState(ctx.cwd);
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
export async function handleModeCommand(args, ctx, pi) {
|
|
879
|
-
const arg = args?.trim();
|
|
880
|
-
const capabilityState = await readCapabilityState(ctx.cwd, ctx, pi?.host);
|
|
881
|
-
const inactiveModeState = await readModeState(ctx.cwd);
|
|
882
|
-
|
|
883
|
-
if (!capabilityState.configured) {
|
|
884
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
885
|
-
ctx.ui.notify(
|
|
886
|
-
"Freeflow is installed but this repo is not set up. Run /setup-freeflow before changing mode.",
|
|
887
|
-
"warning",
|
|
888
|
-
);
|
|
889
|
-
return { changed: false, error: "not_configured" };
|
|
890
|
-
}
|
|
891
|
-
if (!capabilityState.enabled) {
|
|
892
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
893
|
-
ctx.ui.notify(
|
|
894
|
-
"Freeflow is disabled for this repo. Use /freeflow enable or /freeflow settings to re-enable it.",
|
|
895
|
-
"warning",
|
|
896
|
-
);
|
|
897
|
-
return { changed: false, error: "freeflow_disabled" };
|
|
898
|
-
}
|
|
899
|
-
if (!capabilityState.skills.effective) {
|
|
900
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
901
|
-
ctx.ui.notify(
|
|
902
|
-
`Freeflow modes are inactive because Skills are disabled. Configured default mode: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). Enable Skills in /freeflow settings before changing mode.`,
|
|
903
|
-
"warning",
|
|
904
|
-
);
|
|
905
|
-
return { changed: false, error: "skills_disabled" };
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
if (VALID_MODES.has(arg)) {
|
|
909
|
-
if (inactiveModeState.effectiveMode === arg) {
|
|
910
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
911
|
-
const message = inactiveModeState.sessionMode
|
|
912
|
-
? `Freeflow is already in ${arg} mode for this Pi session. No session entry was added. Configured default remains ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}).`
|
|
913
|
-
: `Freeflow is already in ${arg} mode from the configured default (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override was created.`;
|
|
914
|
-
ctx.ui.notify(message, "info");
|
|
915
|
-
return { changed: false, modeState: inactiveModeState };
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
const modeState = await setSessionMode(arg, ctx, pi);
|
|
919
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
920
|
-
ctx.ui.notify(
|
|
921
|
-
`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)}).`,
|
|
922
|
-
"info",
|
|
923
|
-
);
|
|
924
|
-
return { changed: true, modeState };
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
if (RESET_MODE_ARGS.has(arg) || arg === "default") {
|
|
928
|
-
if (!inactiveModeState.sessionMode) {
|
|
929
|
-
setModeStatus(ctx, inactiveModeState, capabilityState);
|
|
930
|
-
ctx.ui.notify(
|
|
931
|
-
`Freeflow is already using the configured default: ${inactiveModeState.defaultMode} (${modeSourceLabel(inactiveModeState.defaultModeSource)}). No session override is active.`,
|
|
932
|
-
"info",
|
|
933
|
-
);
|
|
934
|
-
return { changed: false, modeState: inactiveModeState };
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
const modeState = await setSessionMode(null, ctx, pi);
|
|
938
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
939
|
-
ctx.ui.notify(
|
|
940
|
-
`Freeflow mode reset to configured default: ${modeState.defaultMode} (${modeSourceLabel(modeState.defaultModeSource)}). Session override cleared; .freeflow/local.json and .freeflow/config.json were not changed.`,
|
|
941
|
-
"info",
|
|
942
|
-
);
|
|
943
|
-
return { changed: true, modeState };
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
const modeState = await readModeState(ctx.cwd);
|
|
947
|
-
setModeStatus(ctx, modeState, capabilityState);
|
|
948
|
-
ctx.ui.notify(
|
|
949
|
-
`Freeflow mode is ${modeState.effectiveMode} (${describeModeState(modeState)}). Use /freeflow mode conversation, /freeflow mode workflow, /freeflow mode strict-workflow, or /freeflow mode reset.`,
|
|
950
|
-
"info",
|
|
951
|
-
);
|
|
952
|
-
return { changed: false, modeState, error: arg ? "invalid_mode" : undefined };
|
|
953
|
-
}
|