Implement effective state computation and update apply logic
Co-authored-by: AstroSteveo <34114851+AstroSteveo@users.noreply.github.com>
This commit is contained in:
parent
ea6beac100
commit
18846b91f4
@ -100,8 +100,28 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
collections: 0
|
||||
};
|
||||
|
||||
// Process collections first (they can enable individual items)
|
||||
const enabledItems = new Set();
|
||||
// Import config manager for effective state computation
|
||||
const { computeEffectiveItemStates } = require("./config-manager");
|
||||
|
||||
// Compute effective states using precedence rules
|
||||
const effectiveStates = computeEffectiveItemStates(config);
|
||||
|
||||
// Create sets of effectively enabled items for performance
|
||||
const effectivelyEnabledSets = {
|
||||
prompts: new Set(),
|
||||
instructions: new Set(),
|
||||
chatmodes: new Set()
|
||||
};
|
||||
|
||||
for (const section of ["prompts", "instructions", "chatmodes"]) {
|
||||
for (const [itemName, state] of Object.entries(effectiveStates[section])) {
|
||||
if (state.enabled) {
|
||||
effectivelyEnabledSets[section].add(itemName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count enabled collections for summary
|
||||
if (config.collections) {
|
||||
for (const [collectionName, enabled] of Object.entries(config.collections)) {
|
||||
if (enabled) {
|
||||
@ -109,9 +129,6 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
if (fs.existsSync(collectionPath)) {
|
||||
const collection = parseCollectionYaml(collectionPath);
|
||||
if (collection && collection.items) {
|
||||
collection.items.forEach(item => {
|
||||
enabledItems.add(item.path);
|
||||
});
|
||||
summary.collections++;
|
||||
console.log(`✓ Enabled collection: ${collectionName} (${collection.items.length} items)`);
|
||||
}
|
||||
@ -120,10 +137,8 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
}
|
||||
}
|
||||
|
||||
// Process prompts
|
||||
if (config.prompts) {
|
||||
for (const [promptName, enabled] of Object.entries(config.prompts)) {
|
||||
if (enabled) {
|
||||
// Process prompts using effective states
|
||||
for (const promptName of effectivelyEnabledSets.prompts) {
|
||||
const sourcePath = path.join(rootDir, "prompts", `${promptName}.prompt.md`);
|
||||
if (fs.existsSync(sourcePath)) {
|
||||
const destPath = path.join(outputDir, "prompts", `${promptName}.prompt.md`);
|
||||
@ -132,13 +147,9 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
summary.prompts++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process instructions
|
||||
if (config.instructions) {
|
||||
for (const [instructionName, enabled] of Object.entries(config.instructions)) {
|
||||
if (enabled) {
|
||||
// Process instructions using effective states
|
||||
for (const instructionName of effectivelyEnabledSets.instructions) {
|
||||
const sourcePath = path.join(rootDir, "instructions", `${instructionName}.instructions.md`);
|
||||
if (fs.existsSync(sourcePath)) {
|
||||
const destPath = path.join(outputDir, "instructions", `${instructionName}.instructions.md`);
|
||||
@ -147,13 +158,9 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
summary.instructions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process chat modes
|
||||
if (config.chatmodes) {
|
||||
for (const [chatmodeName, enabled] of Object.entries(config.chatmodes)) {
|
||||
if (enabled) {
|
||||
// Process chat modes using effective states
|
||||
for (const chatmodeName of effectivelyEnabledSets.chatmodes) {
|
||||
const sourcePath = path.join(rootDir, "chatmodes", `${chatmodeName}.chatmode.md`);
|
||||
if (fs.existsSync(sourcePath)) {
|
||||
const destPath = path.join(outputDir, "chatmodes", `${chatmodeName}.chatmode.md`);
|
||||
@ -162,30 +169,6 @@ async function applyConfig(configPath = "awesome-copilot.config.yml") {
|
||||
summary.chatmodes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process items from enabled collections
|
||||
for (const itemPath of enabledItems) {
|
||||
const sourcePath = path.join(rootDir, itemPath);
|
||||
if (fs.existsSync(sourcePath)) {
|
||||
const fileName = path.basename(itemPath);
|
||||
let destPath;
|
||||
|
||||
if (fileName.endsWith('.prompt.md')) {
|
||||
destPath = path.join(outputDir, "prompts", fileName);
|
||||
} else if (fileName.endsWith('.chatmode.md')) {
|
||||
destPath = path.join(outputDir, "chatmodes", fileName);
|
||||
} else if (fileName.endsWith('.instructions.md')) {
|
||||
destPath = path.join(outputDir, "instructions", fileName);
|
||||
}
|
||||
|
||||
if (destPath && !fs.existsSync(destPath)) {
|
||||
copyFile(sourcePath, destPath);
|
||||
copiedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate summary
|
||||
console.log("\n" + "=".repeat(50));
|
||||
|
||||
@ -158,6 +158,90 @@ function getAllAvailableItems(type) {
|
||||
return getAvailableItems(path.join(__dirname, meta.dir), meta.ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute effective item states respecting explicit overrides over collections
|
||||
* @param {Object} config - Configuration object with sections
|
||||
* @returns {Object} Effective states for each section with { itemName: { enabled: boolean, reason: string } }
|
||||
*/
|
||||
function computeEffectiveItemStates(config) {
|
||||
const { parseCollectionYaml } = require("./yaml-parser");
|
||||
|
||||
const effectiveStates = {
|
||||
prompts: {},
|
||||
instructions: {},
|
||||
chatmodes: {}
|
||||
};
|
||||
|
||||
// First, collect all items enabled by collections
|
||||
const collectionEnabledItems = {
|
||||
prompts: new Set(),
|
||||
instructions: new Set(),
|
||||
chatmodes: new Set()
|
||||
};
|
||||
|
||||
if (config.collections) {
|
||||
for (const [collectionName, enabled] of Object.entries(config.collections)) {
|
||||
if (enabled === true) {
|
||||
const collectionPath = path.join(__dirname, "collections", `${collectionName}.collection.yml`);
|
||||
if (fs.existsSync(collectionPath)) {
|
||||
const collection = parseCollectionYaml(collectionPath);
|
||||
if (collection && collection.items) {
|
||||
collection.items.forEach(item => {
|
||||
// Extract item name from path - remove directory and all extensions
|
||||
const itemName = path.basename(item.path).replace(/\.(prompt|instructions|chatmode)\.md$/, '');
|
||||
|
||||
if (item.kind === "prompt") {
|
||||
collectionEnabledItems.prompts.add(itemName);
|
||||
} else if (item.kind === "instruction") {
|
||||
collectionEnabledItems.instructions.add(itemName);
|
||||
} else if (item.kind === "chat-mode") {
|
||||
collectionEnabledItems.chatmodes.add(itemName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For each section, compute effective states
|
||||
for (const section of ["prompts", "instructions", "chatmodes"]) {
|
||||
const sectionConfig = config[section] || {};
|
||||
const collectionEnabled = collectionEnabledItems[section];
|
||||
|
||||
// Get all available items for this section
|
||||
const availableItems = getAllAvailableItems(section);
|
||||
|
||||
for (const itemName of availableItems) {
|
||||
const explicitValue = sectionConfig[itemName];
|
||||
const isEnabledByCollection = collectionEnabled.has(itemName);
|
||||
|
||||
// Precedence rules:
|
||||
// 1. If explicitly set to true or false, use that value
|
||||
// 2. If undefined and enabled by collection, use true
|
||||
// 3. Otherwise, use false
|
||||
|
||||
let enabled = false;
|
||||
let reason = "disabled";
|
||||
|
||||
if (explicitValue === true) {
|
||||
enabled = true;
|
||||
reason = "explicit";
|
||||
} else if (explicitValue === false) {
|
||||
enabled = false;
|
||||
reason = "explicit";
|
||||
} else if (explicitValue === undefined && isEnabledByCollection) {
|
||||
enabled = true;
|
||||
reason = "collection";
|
||||
}
|
||||
|
||||
effectiveStates[section][itemName] = { enabled, reason };
|
||||
}
|
||||
}
|
||||
|
||||
return effectiveStates;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DEFAULT_CONFIG_PATH,
|
||||
CONFIG_SECTIONS,
|
||||
@ -168,5 +252,6 @@ module.exports = {
|
||||
ensureConfigStructure,
|
||||
sortObjectKeys,
|
||||
countEnabledItems,
|
||||
getAllAvailableItems
|
||||
getAllAvailableItems,
|
||||
computeEffectiveItemStates
|
||||
};
|
||||
|
||||
30
test-effective-config.yml
Normal file
30
test-effective-config.yml
Normal file
@ -0,0 +1,30 @@
|
||||
# Awesome Copilot Configuration File
|
||||
# Manual test for effective state computation
|
||||
#
|
||||
# Testing precedence rules with undefined values
|
||||
|
||||
version: "1.0"
|
||||
project:
|
||||
name: "Test Project"
|
||||
description: "Testing effective state precedence"
|
||||
output_directory: ".awesome-copilot"
|
||||
|
||||
collections:
|
||||
testing-automation: true
|
||||
|
||||
prompts:
|
||||
playwright-generate-test: true
|
||||
# Note: playwright-explore-website is not defined (undefined)
|
||||
# Note: csharp-nunit is not defined (undefined)
|
||||
# Note: java-junit is not defined (undefined)
|
||||
ai-prompt-engineering-safety-review: false
|
||||
|
||||
instructions:
|
||||
# Note: playwright-typescript is not defined (undefined)
|
||||
# Note: playwright-python is not defined (undefined)
|
||||
|
||||
chatmodes:
|
||||
# Note: tdd-red is not defined (undefined)
|
||||
# Note: tdd-green is not defined (undefined)
|
||||
# Note: tdd-refactor is not defined (undefined)
|
||||
# Note: playwright-tester is not defined (undefined)
|
||||
Loading…
x
Reference in New Issue
Block a user