agileflow 2.60.0 → 2.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -9
- package/package.json +1 -1
- package/scripts/lib/counter.js +103 -0
- package/src/core/commands/auto.md +1 -0
- package/src/core/commands/babysit.md +170 -29
- package/src/core/commands/board.md +1 -0
- package/src/core/commands/ci.md +1 -0
- package/src/core/commands/compress.md +1 -0
- package/src/core/commands/deploy.md +1 -0
- package/src/core/commands/help.md +1 -0
- package/src/core/commands/research.md +1 -0
- package/src/core/commands/skill/create.md +566 -0
- package/src/core/commands/skill/delete.md +189 -0
- package/src/core/commands/skill/edit.md +245 -0
- package/src/core/commands/skill/list.md +155 -0
- package/src/core/commands/skill/test.md +249 -0
- package/src/core/commands/template.md +1 -0
- package/src/core/commands/tests.md +1 -0
- package/src/core/commands/update.md +1 -0
- package/src/core/commands/velocity.md +1 -0
- package/src/core/experts/refactor/expertise.yaml +17 -12
- package/src/core/templates/claude-settings.advanced.example.json +1 -1
- package/src/core/templates/claude-settings.example.json +1 -1
- package/tools/cli/commands/list.js +8 -13
- package/tools/cli/installers/core/installer.js +20 -19
- package/tools/cli/installers/ide/_base-ide.js +18 -4
- package/tools/cli/installers/ide/claude-code.js +4 -15
- package/tools/cli/installers/ide/codex.js +9 -13
- package/tools/cli/lib/content-injector.js +162 -31
- package/tools/cli/lib/utils.js +87 -0
- package/src/core/skills/acceptance-criteria-generator/SKILL.md +0 -46
- package/src/core/skills/adr-template/SKILL.md +0 -62
- package/src/core/skills/agileflow-acceptance-criteria/SKILL.md +0 -156
- package/src/core/skills/agileflow-adr/SKILL.md +0 -147
- package/src/core/skills/agileflow-adr/examples/database-choice-example.md +0 -122
- package/src/core/skills/agileflow-adr/templates/adr-template.md +0 -69
- package/src/core/skills/agileflow-commit-messages/SKILL.md +0 -130
- package/src/core/skills/agileflow-commit-messages/reference/bad-examples.md +0 -168
- package/src/core/skills/agileflow-commit-messages/reference/good-examples.md +0 -120
- package/src/core/skills/agileflow-commit-messages/scripts/check-attribution.sh +0 -15
- package/src/core/skills/agileflow-epic-planner/SKILL.md +0 -184
- package/src/core/skills/agileflow-retro-facilitator/SKILL.md +0 -119
- package/src/core/skills/agileflow-retro-facilitator/cookbook/4ls.md +0 -86
- package/src/core/skills/agileflow-retro-facilitator/cookbook/glad-sad-mad.md +0 -79
- package/src/core/skills/agileflow-retro-facilitator/cookbook/start-stop-continue.md +0 -142
- package/src/core/skills/agileflow-retro-facilitator/prompts/action-items.md +0 -83
- package/src/core/skills/agileflow-sprint-planner/SKILL.md +0 -212
- package/src/core/skills/agileflow-story-writer/SKILL.md +0 -163
- package/src/core/skills/agileflow-story-writer/examples/good-story-example.md +0 -63
- package/src/core/skills/agileflow-story-writer/templates/story-template.md +0 -44
- package/src/core/skills/agileflow-tech-debt/SKILL.md +0 -215
- package/src/core/skills/api-documentation-generator/SKILL.md +0 -65
- package/src/core/skills/changelog-entry/SKILL.md +0 -55
- package/src/core/skills/commit-message-formatter/SKILL.md +0 -50
- package/src/core/skills/deployment-guide-generator/SKILL.md +0 -84
- package/src/core/skills/diagram-generator/SKILL.md +0 -65
- package/src/core/skills/error-handler-template/SKILL.md +0 -78
- package/src/core/skills/migration-checklist/SKILL.md +0 -82
- package/src/core/skills/pr-description/SKILL.md +0 -65
- package/src/core/skills/sql-schema-generator/SKILL.md +0 -69
- package/src/core/skills/story-skeleton/SKILL.md +0 -34
- package/src/core/skills/test-case-generator/SKILL.md +0 -63
- package/src/core/skills/type-definitions/SKILL.md +0 -65
- package/src/core/skills/validation-schema-generator/SKILL.md +0 -64
- package/src/core/skills/writing-skills/SKILL.md +0 -352
- package/src/core/skills/writing-skills/testing-skills-with-subagents.md +0 -232
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Content Injector - Dynamic content injection for
|
|
2
|
+
* Content Injector - Dynamic content injection for AgileFlow files
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Supports template variables that get replaced at install time:
|
|
5
|
+
*
|
|
6
|
+
* COUNTS:
|
|
7
|
+
* {{COMMAND_COUNT}} - Total number of commands
|
|
8
|
+
* {{AGENT_COUNT}} - Total number of agents
|
|
9
|
+
* {{SKILL_COUNT}} - Total number of skills
|
|
10
|
+
*
|
|
11
|
+
* LISTS:
|
|
12
|
+
* <!-- {{AGENT_LIST}} --> - Full formatted agent list
|
|
13
|
+
* <!-- {{COMMAND_LIST}} --> - Full formatted command list
|
|
14
|
+
*
|
|
15
|
+
* METADATA:
|
|
16
|
+
* {{VERSION}} - AgileFlow version from package.json
|
|
17
|
+
* {{INSTALL_DATE}} - Date of installation (YYYY-MM-DD)
|
|
18
|
+
*
|
|
19
|
+
* FOLDER REFERENCES:
|
|
20
|
+
* {agileflow_folder} - Name of the agileflow folder (e.g., .agileflow)
|
|
21
|
+
* {project-root} - Project root reference
|
|
6
22
|
*/
|
|
7
23
|
|
|
8
24
|
const fs = require('fs');
|
|
9
25
|
const path = require('path');
|
|
26
|
+
|
|
27
|
+
// Use shared modules
|
|
10
28
|
const { parseFrontmatter, normalizeTools } = require('../../../scripts/lib/frontmatter-parser');
|
|
29
|
+
const { countCommands, countAgents, countSkills, getCounts } = require('../../../scripts/lib/counter');
|
|
30
|
+
|
|
31
|
+
// =============================================================================
|
|
32
|
+
// List Generation Functions
|
|
33
|
+
// =============================================================================
|
|
11
34
|
|
|
12
35
|
/**
|
|
13
36
|
* Scan agents directory and generate formatted agent list
|
|
@@ -15,17 +38,16 @@ const { parseFrontmatter, normalizeTools } = require('../../../scripts/lib/front
|
|
|
15
38
|
* @returns {string} Formatted agent list
|
|
16
39
|
*/
|
|
17
40
|
function generateAgentList(agentsDir) {
|
|
41
|
+
if (!fs.existsSync(agentsDir)) return '';
|
|
42
|
+
|
|
18
43
|
const files = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
19
44
|
const agents = [];
|
|
20
45
|
|
|
21
46
|
for (const file of files) {
|
|
22
47
|
const filePath = path.join(agentsDir, file);
|
|
23
48
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
24
|
-
|
|
25
|
-
// Parse frontmatter using shared parser
|
|
26
49
|
const frontmatter = parseFrontmatter(content);
|
|
27
50
|
|
|
28
|
-
// Skip if no frontmatter found
|
|
29
51
|
if (!frontmatter || Object.keys(frontmatter).length === 0) {
|
|
30
52
|
continue;
|
|
31
53
|
}
|
|
@@ -38,17 +60,15 @@ function generateAgentList(agentsDir) {
|
|
|
38
60
|
});
|
|
39
61
|
}
|
|
40
62
|
|
|
41
|
-
// Sort alphabetically by name
|
|
42
63
|
agents.sort((a, b) => a.name.localeCompare(b.name));
|
|
43
64
|
|
|
44
|
-
// Generate formatted output
|
|
45
65
|
let output = `**AVAILABLE AGENTS (${agents.length} total)**:\n\n`;
|
|
46
66
|
|
|
47
67
|
agents.forEach((agent, index) => {
|
|
48
68
|
output += `${index + 1}. **${agent.name}** (model: ${agent.model})\n`;
|
|
49
69
|
output += ` - **Purpose**: ${agent.description}\n`;
|
|
50
70
|
output += ` - **Tools**: ${agent.tools.join(', ')}\n`;
|
|
51
|
-
output += ` - **Usage**: \`subagent_type: "
|
|
71
|
+
output += ` - **Usage**: \`subagent_type: "agileflow-${agent.name}"\`\n`;
|
|
52
72
|
output += `\n`;
|
|
53
73
|
});
|
|
54
74
|
|
|
@@ -61,18 +81,18 @@ function generateAgentList(agentsDir) {
|
|
|
61
81
|
* @returns {string} Formatted command list
|
|
62
82
|
*/
|
|
63
83
|
function generateCommandList(commandsDir) {
|
|
64
|
-
|
|
84
|
+
if (!fs.existsSync(commandsDir)) return '';
|
|
85
|
+
|
|
65
86
|
const commands = [];
|
|
66
87
|
|
|
67
|
-
|
|
88
|
+
// Scan main commands
|
|
89
|
+
const mainFiles = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
|
|
90
|
+
for (const file of mainFiles) {
|
|
68
91
|
const filePath = path.join(commandsDir, file);
|
|
69
92
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
70
|
-
|
|
71
|
-
// Parse frontmatter using shared parser
|
|
72
93
|
const frontmatter = parseFrontmatter(content);
|
|
73
94
|
const cmdName = path.basename(file, '.md');
|
|
74
95
|
|
|
75
|
-
// Skip if no frontmatter found
|
|
76
96
|
if (!frontmatter || Object.keys(frontmatter).length === 0) {
|
|
77
97
|
continue;
|
|
78
98
|
}
|
|
@@ -84,10 +104,34 @@ function generateCommandList(commandsDir) {
|
|
|
84
104
|
});
|
|
85
105
|
}
|
|
86
106
|
|
|
87
|
-
//
|
|
107
|
+
// Scan subdirectories (e.g., session/)
|
|
108
|
+
const entries = fs.readdirSync(commandsDir, { withFileTypes: true });
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (entry.isDirectory()) {
|
|
111
|
+
const subDir = path.join(commandsDir, entry.name);
|
|
112
|
+
const subFiles = fs.readdirSync(subDir).filter(f => f.endsWith('.md'));
|
|
113
|
+
|
|
114
|
+
for (const file of subFiles) {
|
|
115
|
+
const filePath = path.join(subDir, file);
|
|
116
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
117
|
+
const frontmatter = parseFrontmatter(content);
|
|
118
|
+
const cmdName = `${entry.name}:${path.basename(file, '.md')}`;
|
|
119
|
+
|
|
120
|
+
if (!frontmatter || Object.keys(frontmatter).length === 0) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
commands.push({
|
|
125
|
+
name: cmdName,
|
|
126
|
+
description: frontmatter.description || '',
|
|
127
|
+
argumentHint: frontmatter['argument-hint'] || '',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
88
133
|
commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
89
134
|
|
|
90
|
-
// Generate formatted output
|
|
91
135
|
let output = `Available commands (${commands.length} total):\n`;
|
|
92
136
|
|
|
93
137
|
commands.forEach(cmd => {
|
|
@@ -98,33 +142,120 @@ function generateCommandList(commandsDir) {
|
|
|
98
142
|
return output;
|
|
99
143
|
}
|
|
100
144
|
|
|
145
|
+
// =============================================================================
|
|
146
|
+
// Main Injection Function
|
|
147
|
+
// =============================================================================
|
|
148
|
+
|
|
101
149
|
/**
|
|
102
|
-
* Inject
|
|
103
|
-
* @param {string}
|
|
104
|
-
* @param {
|
|
105
|
-
* @param {string}
|
|
106
|
-
* @
|
|
150
|
+
* Inject all template variables into content
|
|
151
|
+
* @param {string} content - Template content with placeholders
|
|
152
|
+
* @param {Object} context - Context for replacements
|
|
153
|
+
* @param {string} context.coreDir - Path to core directory (commands/, agents/, skills/)
|
|
154
|
+
* @param {string} context.agileflowFolder - AgileFlow folder name
|
|
155
|
+
* @param {string} context.version - AgileFlow version
|
|
156
|
+
* @returns {string} Content with all placeholders replaced
|
|
107
157
|
*/
|
|
108
|
-
function injectContent(
|
|
109
|
-
|
|
158
|
+
function injectContent(content, context = {}) {
|
|
159
|
+
const { coreDir, agileflowFolder = '.agileflow', version = 'unknown' } = context;
|
|
160
|
+
|
|
161
|
+
let result = content;
|
|
110
162
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
163
|
+
// Get counts if core directory is available
|
|
164
|
+
let counts = { commands: 0, agents: 0, skills: 0 };
|
|
165
|
+
if (coreDir && fs.existsSync(coreDir)) {
|
|
166
|
+
counts = getCounts(coreDir);
|
|
115
167
|
}
|
|
116
168
|
|
|
117
|
-
// Replace {{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
169
|
+
// Replace count placeholders (both formats: {{X}} and <!-- {{X}} -->)
|
|
170
|
+
result = result.replace(/\{\{COMMAND_COUNT\}\}/g, String(counts.commands));
|
|
171
|
+
result = result.replace(/\{\{AGENT_COUNT\}\}/g, String(counts.agents));
|
|
172
|
+
result = result.replace(/\{\{SKILL_COUNT\}\}/g, String(counts.skills));
|
|
173
|
+
|
|
174
|
+
// Replace metadata placeholders
|
|
175
|
+
result = result.replace(/\{\{VERSION\}\}/g, version);
|
|
176
|
+
result = result.replace(/\{\{INSTALL_DATE\}\}/g, new Date().toISOString().split('T')[0]);
|
|
177
|
+
|
|
178
|
+
// Replace list placeholders (only if core directory available)
|
|
179
|
+
if (coreDir && fs.existsSync(coreDir)) {
|
|
180
|
+
if (result.includes('{{AGENT_LIST}}')) {
|
|
181
|
+
const agentList = generateAgentList(path.join(coreDir, 'agents'));
|
|
182
|
+
result = result.replace(/<!-- \{\{AGENT_LIST\}\} -->/g, agentList);
|
|
183
|
+
result = result.replace(/\{\{AGENT_LIST\}\}/g, agentList);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (result.includes('{{COMMAND_LIST}}')) {
|
|
187
|
+
const commandList = generateCommandList(path.join(coreDir, 'commands'));
|
|
188
|
+
result = result.replace(/<!-- \{\{COMMAND_LIST\}\} -->/g, commandList);
|
|
189
|
+
result = result.replace(/\{\{COMMAND_LIST\}\}/g, commandList);
|
|
190
|
+
}
|
|
121
191
|
}
|
|
122
192
|
|
|
193
|
+
// Replace folder placeholders
|
|
194
|
+
result = result.replace(/\{agileflow_folder\}/g, agileflowFolder);
|
|
195
|
+
result = result.replace(/\{project-root\}/g, '{project-root}'); // Keep as-is for runtime
|
|
196
|
+
|
|
123
197
|
return result;
|
|
124
198
|
}
|
|
125
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Check if content has any template variables
|
|
202
|
+
* @param {string} content - Content to check
|
|
203
|
+
* @returns {boolean} True if content has placeholders
|
|
204
|
+
*/
|
|
205
|
+
function hasPlaceholders(content) {
|
|
206
|
+
const patterns = [
|
|
207
|
+
/\{\{COMMAND_COUNT\}\}/,
|
|
208
|
+
/\{\{AGENT_COUNT\}\}/,
|
|
209
|
+
/\{\{SKILL_COUNT\}\}/,
|
|
210
|
+
/\{\{VERSION\}\}/,
|
|
211
|
+
/\{\{INSTALL_DATE\}\}/,
|
|
212
|
+
/\{\{AGENT_LIST\}\}/,
|
|
213
|
+
/\{\{COMMAND_LIST\}\}/,
|
|
214
|
+
/\{agileflow_folder\}/,
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
return patterns.some(pattern => pattern.test(content));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* List all supported placeholders
|
|
222
|
+
* @returns {Object} Placeholder documentation
|
|
223
|
+
*/
|
|
224
|
+
function getPlaceholderDocs() {
|
|
225
|
+
return {
|
|
226
|
+
counts: {
|
|
227
|
+
'{{COMMAND_COUNT}}': 'Total number of slash commands',
|
|
228
|
+
'{{AGENT_COUNT}}': 'Total number of specialized agents',
|
|
229
|
+
'{{SKILL_COUNT}}': 'Total number of skills',
|
|
230
|
+
},
|
|
231
|
+
lists: {
|
|
232
|
+
'<!-- {{AGENT_LIST}} -->': 'Full formatted agent list with details',
|
|
233
|
+
'<!-- {{COMMAND_LIST}} -->': 'Full formatted command list',
|
|
234
|
+
},
|
|
235
|
+
metadata: {
|
|
236
|
+
'{{VERSION}}': 'AgileFlow version from package.json',
|
|
237
|
+
'{{INSTALL_DATE}}': 'Installation date (YYYY-MM-DD)',
|
|
238
|
+
},
|
|
239
|
+
folders: {
|
|
240
|
+
'{agileflow_folder}': 'Name of the AgileFlow folder',
|
|
241
|
+
'{project-root}': 'Project root reference (kept as-is)',
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
126
246
|
module.exports = {
|
|
247
|
+
// Count functions
|
|
248
|
+
countCommands,
|
|
249
|
+
countAgents,
|
|
250
|
+
countSkills,
|
|
251
|
+
getCounts,
|
|
252
|
+
|
|
253
|
+
// List generation
|
|
127
254
|
generateAgentList,
|
|
128
255
|
generateCommandList,
|
|
256
|
+
|
|
257
|
+
// Main injection
|
|
129
258
|
injectContent,
|
|
259
|
+
hasPlaceholders,
|
|
260
|
+
getPlaceholderDocs,
|
|
130
261
|
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Common utility functions used across the CLI.
|
|
5
|
+
* Consolidates duplicated code from installer.js, doctor.js, etc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Calculate SHA256 hash of data and return as hex string
|
|
13
|
+
* @param {string|Buffer} data - Data to hash
|
|
14
|
+
* @returns {string} Hex-encoded SHA256 hash
|
|
15
|
+
*/
|
|
16
|
+
function sha256Hex(data) {
|
|
17
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Convert a file path to POSIX format (forward slashes)
|
|
22
|
+
* @param {string} filePath - Path to convert
|
|
23
|
+
* @returns {string} POSIX-style path
|
|
24
|
+
*/
|
|
25
|
+
function toPosixPath(filePath) {
|
|
26
|
+
return filePath.split(path.sep).join('/');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Generate a safe timestamp string for use in file/folder names
|
|
31
|
+
* @param {Date} date - Date to format (defaults to now)
|
|
32
|
+
* @returns {string} Timestamp like "2025-12-27T10-30-45-123Z"
|
|
33
|
+
*/
|
|
34
|
+
function safeTimestampForPath(date = new Date()) {
|
|
35
|
+
return date.toISOString().replace(/[:.]/g, '-');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Compare two semantic version strings
|
|
40
|
+
* @param {string} v1 - First version (e.g., "2.61.0")
|
|
41
|
+
* @param {string} v2 - Second version (e.g., "2.60.0")
|
|
42
|
+
* @returns {number} -1 if v1 < v2, 0 if equal, 1 if v1 > v2
|
|
43
|
+
*/
|
|
44
|
+
function compareVersions(v1, v2) {
|
|
45
|
+
const parts1 = v1.replace(/^v/, '').split('.').map(Number);
|
|
46
|
+
const parts2 = v2.replace(/^v/, '').split('.').map(Number);
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
49
|
+
const p1 = parts1[i] || 0;
|
|
50
|
+
const p2 = parts2[i] || 0;
|
|
51
|
+
if (p1 < p2) return -1;
|
|
52
|
+
if (p1 > p2) return 1;
|
|
53
|
+
}
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create a debug logger function
|
|
59
|
+
* @param {boolean} enabled - Whether debug logging is enabled
|
|
60
|
+
* @param {string} prefix - Optional prefix for log messages
|
|
61
|
+
* @returns {Function} Debug log function
|
|
62
|
+
*/
|
|
63
|
+
function createDebugLogger(enabled, prefix = '') {
|
|
64
|
+
return (...args) => {
|
|
65
|
+
if (enabled) {
|
|
66
|
+
if (prefix) {
|
|
67
|
+
console.log(`[${prefix}]`, ...args);
|
|
68
|
+
} else {
|
|
69
|
+
console.log(...args);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Brand color for AgileFlow (burnt orange/terracotta)
|
|
77
|
+
*/
|
|
78
|
+
const BRAND_COLOR = '#e8683a';
|
|
79
|
+
|
|
80
|
+
module.exports = {
|
|
81
|
+
sha256Hex,
|
|
82
|
+
toPosixPath,
|
|
83
|
+
safeTimestampForPath,
|
|
84
|
+
compareVersions,
|
|
85
|
+
createDebugLogger,
|
|
86
|
+
BRAND_COLOR,
|
|
87
|
+
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: acceptance-criteria-generator
|
|
3
|
-
description: Generate properly-formatted Given/When/Then acceptance criteria for user stories
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# acceptance-criteria-generator
|
|
7
|
-
|
|
8
|
-
Generate properly-formatted Given/When/Then acceptance criteria.
|
|
9
|
-
|
|
10
|
-
## Activation Keywords
|
|
11
|
-
- "AC", "acceptance criteria", "Given When Then", "given when then", "acceptance", "criteria"
|
|
12
|
-
|
|
13
|
-
## When to Use
|
|
14
|
-
- User is writing acceptance criteria
|
|
15
|
-
- Need to format AC in proper Given/When/Then structure
|
|
16
|
-
- Ensuring clarity and testability of requirements
|
|
17
|
-
|
|
18
|
-
## What This Does
|
|
19
|
-
Takes user's plain English requirements and converts to structured Given/When/Then format:
|
|
20
|
-
- **Given**: Initial state/preconditions
|
|
21
|
-
- **When**: User action or trigger
|
|
22
|
-
- **Then**: Expected outcome/result
|
|
23
|
-
|
|
24
|
-
Generates multiple AC items if needed (typically 2-5 per story).
|
|
25
|
-
|
|
26
|
-
Ensures each criterion is:
|
|
27
|
-
- Testable (not vague)
|
|
28
|
-
- Independent (doesn't depend on other AC)
|
|
29
|
-
- Clear (unambiguous language)
|
|
30
|
-
- Measurable (has a clear success/failure)
|
|
31
|
-
|
|
32
|
-
## Output
|
|
33
|
-
Well-formatted acceptance criteria ready to add to story.
|
|
34
|
-
|
|
35
|
-
## Example Activation
|
|
36
|
-
User: "User should be able to log in with email and password, and receive a JWT token"
|
|
37
|
-
Skill: Generates:
|
|
38
|
-
```
|
|
39
|
-
- **Given** a registered user with valid email and password
|
|
40
|
-
**When** user POSTs to /api/auth/login with credentials
|
|
41
|
-
**Then** they receive a 200 response with JWT token (24h expiration)
|
|
42
|
-
|
|
43
|
-
- **Given** a user enters wrong password
|
|
44
|
-
**When** they attempt login
|
|
45
|
-
**Then** they receive 401 Unauthorized and rate limit applied
|
|
46
|
-
```
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: adr-template
|
|
3
|
-
description: Generate Architecture Decision Record structure with context/decision/consequences
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# adr-template
|
|
7
|
-
|
|
8
|
-
Generate Architecture Decision Record structure with context/decision/consequences.
|
|
9
|
-
|
|
10
|
-
## Activation Keywords
|
|
11
|
-
- "ADR", "architecture decision", "decision record", "adr template"
|
|
12
|
-
|
|
13
|
-
## When to Use
|
|
14
|
-
- Major architectural decisions made during implementation
|
|
15
|
-
- Documenting why a technology/pattern was chosen
|
|
16
|
-
- Recording decision trade-offs and alternatives considered
|
|
17
|
-
|
|
18
|
-
## What This Does
|
|
19
|
-
Generates complete ADR structure with:
|
|
20
|
-
- **Title**: Clear, concise decision title
|
|
21
|
-
- **Status**: Proposed, Accepted, Deprecated, Superseded
|
|
22
|
-
- **Context**: Why this decision was needed, what problem does it solve
|
|
23
|
-
- **Decision**: What was decided and why
|
|
24
|
-
- **Consequences**: Positive outcomes and risks introduced
|
|
25
|
-
- **Alternatives**: Other options considered and why rejected
|
|
26
|
-
- **Related Stories**: Links to affected user stories
|
|
27
|
-
|
|
28
|
-
Includes proper YAML frontmatter for integration with status.json.
|
|
29
|
-
|
|
30
|
-
## Output
|
|
31
|
-
Ready-to-use ADR file in docs/03-decisions/adr-XXXX.md format
|
|
32
|
-
|
|
33
|
-
## Example Activation
|
|
34
|
-
User: "We decided to use JWT for authentication instead of sessions"
|
|
35
|
-
Skill: Generates:
|
|
36
|
-
```
|
|
37
|
-
---
|
|
38
|
-
adr_id: ADR-0042
|
|
39
|
-
title: Use JWT for stateless authentication
|
|
40
|
-
status: accepted
|
|
41
|
-
date: 2025-10-28
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Context
|
|
45
|
-
Application needs scalable authentication across microservices.
|
|
46
|
-
Session-based auth requires shared state/cache.
|
|
47
|
-
|
|
48
|
-
## Decision
|
|
49
|
-
Adopt JWT (JSON Web Tokens) for stateless authentication.
|
|
50
|
-
|
|
51
|
-
## Consequences
|
|
52
|
-
✅ Benefits: Scalable, distributed, microservice-friendly
|
|
53
|
-
❌ Risks: Token revocation requires blacklist, larger payload
|
|
54
|
-
|
|
55
|
-
## Alternatives Considered
|
|
56
|
-
1. Session + Redis: Requires shared state
|
|
57
|
-
2. OAuth2: Overkill for internal auth
|
|
58
|
-
|
|
59
|
-
## Related Stories
|
|
60
|
-
- US-0001: User Login API
|
|
61
|
-
- US-0002: Password Reset
|
|
62
|
-
```
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: agileflow-acceptance-criteria
|
|
3
|
-
description: Generates detailed Given/When/Then acceptance criteria when user describes feature behavior or requirements. Enhances user stories with testable scenarios.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# AgileFlow Acceptance Criteria
|
|
7
|
-
|
|
8
|
-
Automatically generates detailed, testable acceptance criteria in Given/When/Then (Gherkin) format from feature discussions and requirements.
|
|
9
|
-
|
|
10
|
-
## When to Use
|
|
11
|
-
|
|
12
|
-
This skill activates when:
|
|
13
|
-
- User describes how a feature should behave
|
|
14
|
-
- Discussing user workflows or interactions
|
|
15
|
-
- Keywords: "acceptance criteria", "test scenarios", "should work like"
|
|
16
|
-
- Creating or reviewing user stories
|
|
17
|
-
- User describes "when user does X, then Y should happen"
|
|
18
|
-
|
|
19
|
-
## What This Does
|
|
20
|
-
|
|
21
|
-
1. Extracts feature behavior from user discussions
|
|
22
|
-
2. Identifies different scenarios (happy path, errors, edge cases)
|
|
23
|
-
3. Generates criteria in Given/When/Then format
|
|
24
|
-
4. Ensures criteria are specific, testable, and independent
|
|
25
|
-
5. Enhances story's AC section
|
|
26
|
-
|
|
27
|
-
## Instructions
|
|
28
|
-
|
|
29
|
-
1. **Listen for behavior descriptions**: User explains "when X happens, Y should occur"
|
|
30
|
-
|
|
31
|
-
2. **Extract scenarios**:
|
|
32
|
-
- Happy path (normal use)
|
|
33
|
-
- Error cases (what goes wrong)
|
|
34
|
-
- Edge cases (boundary conditions)
|
|
35
|
-
- Permission-based scenarios
|
|
36
|
-
|
|
37
|
-
3. **Generate criteria**:
|
|
38
|
-
- One AC per distinct scenario
|
|
39
|
-
- Clear, unambiguous language
|
|
40
|
-
- Make it testable (observable outcome)
|
|
41
|
-
- Include edge cases
|
|
42
|
-
|
|
43
|
-
4. **Add to story**: If working on a story, enhance its AC section
|
|
44
|
-
|
|
45
|
-
## Given/When/Then Format
|
|
46
|
-
|
|
47
|
-
```markdown
|
|
48
|
-
### AC#: [Criterion Name]
|
|
49
|
-
**Given** [initial context or precondition]
|
|
50
|
-
**When** [user action or trigger event]
|
|
51
|
-
**Then** [expected outcome or system behavior]
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
**Given** (Precondition):
|
|
55
|
-
- User's current state, system state, data that exists, permissions/roles
|
|
56
|
-
- Example: "Given I am logged in as an admin"
|
|
57
|
-
|
|
58
|
-
**When** (Action):
|
|
59
|
-
- What the user does, event that occurs, API call made
|
|
60
|
-
- Example: "When I click the 'Add to Cart' button"
|
|
61
|
-
|
|
62
|
-
**Then** (Outcome):
|
|
63
|
-
- What the user sees, system state changes, data modifications, error messages
|
|
64
|
-
- Example: "Then the item is added to my cart"
|
|
65
|
-
|
|
66
|
-
## Common Patterns
|
|
67
|
-
|
|
68
|
-
**Happy Path**:
|
|
69
|
-
```markdown
|
|
70
|
-
### AC1: Successful Login
|
|
71
|
-
**Given** I am on the login page
|
|
72
|
-
**When** I enter valid credentials and click "Login"
|
|
73
|
-
**Then** I am redirected to my dashboard
|
|
74
|
-
**And** I see a welcome message with my name
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
**Error Handling**:
|
|
78
|
-
```markdown
|
|
79
|
-
### AC2: Invalid Password
|
|
80
|
-
**Given** I am on the login page
|
|
81
|
-
**When** I enter a valid email but incorrect password
|
|
82
|
-
**Then** I see an error message "Invalid credentials"
|
|
83
|
-
**And** I remain on the login page
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**Edge Cases**:
|
|
87
|
-
```markdown
|
|
88
|
-
### AC3: Account Locked After Failed Attempts
|
|
89
|
-
**Given** I have failed to login 4 times
|
|
90
|
-
**When** I attempt to login with incorrect password again
|
|
91
|
-
**Then** my account is locked for 30 minutes
|
|
92
|
-
**And** an email is sent to my registered address
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**Permission-Based**:
|
|
96
|
-
```markdown
|
|
97
|
-
### AC4: Admin-Only Feature Access
|
|
98
|
-
**Given** I am logged in as a regular user
|
|
99
|
-
**When** I try to access the admin dashboard
|
|
100
|
-
**Then** I see a 403 Forbidden error
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**Form Validation**:
|
|
104
|
-
```markdown
|
|
105
|
-
### AC1: Email Format Validation
|
|
106
|
-
**Given** I am filling out the registration form
|
|
107
|
-
**When** I enter an invalid email format (missing @)
|
|
108
|
-
**Then** I see an error "Please enter a valid email address"
|
|
109
|
-
**And** the submit button remains disabled
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Multiple Conditions
|
|
113
|
-
|
|
114
|
-
Use **And** for additional conditions:
|
|
115
|
-
```markdown
|
|
116
|
-
**Given** I am logged in
|
|
117
|
-
**And** I have items in my cart
|
|
118
|
-
**When** I click "Checkout"
|
|
119
|
-
**Then** I am redirected to payment page
|
|
120
|
-
**And** I see my cart summary
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
Use **But** for contrasting outcomes:
|
|
124
|
-
```markdown
|
|
125
|
-
**Given** I am on the search page
|
|
126
|
-
**When** I search for "nonexistent product"
|
|
127
|
-
**Then** I see "No results found" message
|
|
128
|
-
**But** I see suggested categories
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## Quality Checklist
|
|
132
|
-
|
|
133
|
-
Good acceptance criteria are:
|
|
134
|
-
- [ ] **Specific**: Clearly describes one scenario
|
|
135
|
-
- [ ] **Testable**: Can be verified with a test
|
|
136
|
-
- [ ] **Independent**: Doesn't depend on order of execution
|
|
137
|
-
- [ ] **Unambiguous**: Only one interpretation possible
|
|
138
|
-
- [ ] **Complete**: Covers happy path, errors, and edge cases
|
|
139
|
-
- [ ] **User-focused**: Written from user's perspective
|
|
140
|
-
- [ ] **3-7 criteria per story**: Enough coverage, not excessive
|
|
141
|
-
|
|
142
|
-
## Integration
|
|
143
|
-
|
|
144
|
-
- **agileflow-story-writer**: Automatically enhances story AC sections
|
|
145
|
-
- **agileflow-sprint-planner**: Helps estimate story complexity from AC count
|
|
146
|
-
- **agileflow-tech-debt**: Identifies missing test coverage from AC
|
|
147
|
-
|
|
148
|
-
## Notes
|
|
149
|
-
|
|
150
|
-
- Aim for 3-7 acceptance criteria per story
|
|
151
|
-
- Too few = incomplete requirements
|
|
152
|
-
- Too many = story should be split
|
|
153
|
-
- Cover at least one error case per story
|
|
154
|
-
- Include accessibility criteria when relevant
|
|
155
|
-
- Consider mobile vs desktop differences
|
|
156
|
-
- Think about internationalization if applicable
|