agileflow 2.82.5 → 2.84.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.
@@ -184,6 +184,47 @@ When `VISUAL=true` is specified, the loop adds screenshot verification:
184
184
  **Setup requirement:**
185
185
  Run `/agileflow:configure` and select "Set up Visual E2E testing" to install Playwright and create e2e tests.
186
186
 
187
+ ### Visual Mode Auto-Detection (IMPORTANT)
188
+
189
+ **Check the context output** from `obtain-context.js` for Visual E2E status.
190
+
191
+ **If "📸 VISUAL E2E TESTING: ENABLED" appears:**
192
+
193
+ When presenting task options for UI-focused work, **proactively suggest VISUAL mode**:
194
+
195
+ ```
196
+ This epic involves UI work. Visual E2E is configured.
197
+
198
+ Suggested command:
199
+ /agileflow:babysit EPIC=EP-0042 MODE=loop VISUAL=true
200
+
201
+ Visual Mode ensures:
202
+ - Screenshots are captured and verified
203
+ - Minimum 2 iterations (prevents premature completion)
204
+ - Both tests AND visual verification must pass
205
+ ```
206
+
207
+ **Detection criteria for suggesting VISUAL=true:**
208
+ | Indicator | Suggest VISUAL? |
209
+ |-----------|-----------------|
210
+ | Epic mentions "UI", "component", "styling" | Yes |
211
+ | Stories have owner: AG-UI | Yes |
212
+ | Files involve src/components/, *.css, *.tsx | Yes |
213
+ | Work is API/backend only | No |
214
+ | Work is CLI/scripts only | No |
215
+
216
+ **If "VISUAL E2E TESTING: NOT CONFIGURED" appears:**
217
+
218
+ For UI work, suggest setup:
219
+ ```
220
+ This is UI work. Visual E2E not configured.
221
+
222
+ To enable screenshot verification:
223
+ /agileflow:configure → Visual E2E testing
224
+
225
+ This helps catch visual issues that tests miss (wrong colors, broken layouts).
226
+ ```
227
+
187
228
  ### Loop Control Commands
188
229
 
189
230
  ```bash
@@ -662,6 +703,7 @@ Based on your project state:
662
703
  - Delegate complex work to experts
663
704
  - If stuck 2+ times → research prompt
664
705
  - Use state narration markers (📍🔀🔄⚠️✅) for visibility
706
+ - **STORY CLAIMING**: Claim stories before working, skip 🔒 claimed stories in suggestions
665
707
 
666
708
  <!-- COMPACT_SUMMARY_END -->
667
709
 
@@ -1096,6 +1138,82 @@ After loading context, analyze and present ranked options:
1096
1138
 
1097
1139
  ---
1098
1140
 
1141
+ ## STORY CLAIMING (Multi-Session Coordination)
1142
+
1143
+ When multiple Claude Code sessions work in the same repo, story claiming prevents conflicts.
1144
+
1145
+ ### How It Works
1146
+
1147
+ 1. **Claim on Selection**: When user selects a story to work on, claim it:
1148
+ ```bash
1149
+ node .agileflow/scripts/lib/story-claiming.js claim US-0042
1150
+ ```
1151
+
1152
+ 2. **Check Before Suggesting**: Filter out claimed stories from suggestions:
1153
+ - Stories with 🔒 badge are claimed by OTHER sessions
1154
+ - Stories with ✓ badge are claimed by THIS session (can continue)
1155
+ - Stories without badge are available
1156
+
1157
+ 3. **Release on Completion**: When story is marked "done", release claim:
1158
+ ```bash
1159
+ node .agileflow/scripts/lib/story-claiming.js release US-0042
1160
+ ```
1161
+
1162
+ ### Story Badges in AskUserQuestion
1163
+
1164
+ | Badge | Meaning | Action |
1165
+ |-------|---------|--------|
1166
+ | ⭐ | Ready, available | Can select |
1167
+ | 🔒 | Claimed by other session | **DO NOT suggest** (or show as disabled) |
1168
+ | ✓ | Claimed by this session | Continue working |
1169
+
1170
+ ### Claiming Flow
1171
+
1172
+ ```
1173
+ User: "Work on US-0042"
1174
+
1175
+ Check: Is US-0042 claimed?
1176
+
1177
+ ┌──────────────┐ ┌──────────────────┐
1178
+ │ Not claimed │ │ Claimed by other │
1179
+ └──────────────┘ └──────────────────┘
1180
+ ↓ ↓
1181
+ Claim it, proceed Show warning:
1182
+ "US-0042 is being worked on
1183
+ by Session 2 (../project-auth).
1184
+
1185
+ Pick a different story to
1186
+ avoid merge conflicts."
1187
+ ```
1188
+
1189
+ ### Commands
1190
+
1191
+ ```bash
1192
+ # Claim a story
1193
+ node .agileflow/scripts/lib/story-claiming.js claim US-0042
1194
+
1195
+ # Release a story
1196
+ node .agileflow/scripts/lib/story-claiming.js release US-0042
1197
+
1198
+ # Check if claimed
1199
+ node .agileflow/scripts/lib/story-claiming.js check US-0042
1200
+
1201
+ # List stories claimed by others
1202
+ node .agileflow/scripts/lib/story-claiming.js others
1203
+
1204
+ # Clean stale claims (dead PIDs)
1205
+ node .agileflow/scripts/lib/story-claiming.js cleanup
1206
+ ```
1207
+
1208
+ ### Important Rules
1209
+
1210
+ - **Always claim before working**: Prevents conflicts
1211
+ - **Stale claims auto-expire**: If session PID dies or 4 hours pass
1212
+ - **Force claim available**: `--force` flag overrides (use sparingly)
1213
+ - **Release on completion**: Or let auto-expiry handle it
1214
+
1215
+ ---
1216
+
1099
1217
  ## KNOWLEDGE INDEX
1100
1218
 
1101
1219
  **Context script provides:**
@@ -190,7 +190,7 @@ If `hasConflicts: true`:
190
190
  ```
191
191
  ⚠️ Merge conflicts detected!
192
192
 
193
- This branch has conflicts with {mainBranch} that need to be resolved manually.
193
+ This branch has conflicts with {mainBranch}. Smart merge can attempt automatic resolution.
194
194
  ```
195
195
 
196
196
  Then show conflict options:
@@ -201,6 +201,8 @@ AskUserQuestion:
201
201
  header: "Merge conflicts"
202
202
  multiSelect: false
203
203
  options:
204
+ - label: "Auto-resolve conflicts (Recommended)"
205
+ description: "Smart merge will resolve based on file types automatically"
204
206
  - label: "Resolve manually"
205
207
  description: "Keep session active and resolve conflicts yourself"
206
208
  - label: "End session without merging"
@@ -209,6 +211,40 @@ AskUserQuestion:
209
211
  description: "Keep session as-is"
210
212
  ```
211
213
 
214
+ If "Auto-resolve conflicts" selected:
215
+ ```bash
216
+ node .agileflow/scripts/session-manager.js smart-merge {session_id} --strategy={squash|merge}
217
+ ```
218
+
219
+ The smart merge will:
220
+ 1. Categorize conflicting files by type (docs, tests, schema, config, source)
221
+ 2. Apply appropriate resolution strategy per file type
222
+ 3. Log all auto-resolutions for audit
223
+
224
+ Display result:
225
+ ```
226
+ ✓ Conflicts auto-resolved!
227
+
228
+ Files resolved:
229
+ 📄 docs/README.md → accept_both (Documentation kept from both)
230
+ 🧪 tests/api.test.ts → accept_both (Tests kept from both)
231
+ ⚙️ package.json → merge_keys (Config merged)
232
+ 📝 src/api.ts → intelligent_merge (Source merged)
233
+
234
+ Merge log saved to: .agileflow/sessions/merge-log.json
235
+ ```
236
+
237
+ If auto-resolution fails:
238
+ ```
239
+ ⚠️ Some conflicts could not be auto-resolved:
240
+
241
+ ❌ src/complex.ts → Changes overlap in same code block
242
+
243
+ Options:
244
+ • Resolve manually (see instructions below)
245
+ • End session without merging
246
+ ```
247
+
212
248
  If "Resolve manually" selected, show instructions:
213
249
  ```
214
250
  To resolve conflicts manually:
@@ -409,7 +445,13 @@ node .agileflow/scripts/session-manager.js merge-preview {session_id}
409
445
  Display commits and files to be merged.
410
446
 
411
447
  **Step 3: Check conflicts**
412
- If `hasConflicts: true` → Show conflict options → EXIT or manual resolution
448
+ If `hasConflicts: true` → Show conflict options (auto-resolve/manual/end/cancel)
449
+
450
+ **Step 3a: If auto-resolve selected**
451
+ ```bash
452
+ node .agileflow/scripts/session-manager.js smart-merge {session_id} --strategy={squash|merge}
453
+ ```
454
+ Smart merge auto-resolves by file type: docs→accept_both, tests→accept_both, config→merge_keys, source→theirs
413
455
 
414
456
  **Step 4: Choose strategy**
415
457
  ```xml
@@ -1,178 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * AgileFlow TUI Dashboard
5
- *
6
- * BETA - Internal use only, not publicly documented
7
- *
8
- * Usage: npx agileflow start
9
- */
10
-
11
- const path = require('path');
12
- const fs = require('fs');
13
- const { c: colors } = require('../../../lib/colors');
14
-
15
- function showBetaWarning() {
16
- console.log('');
17
- console.log(
18
- `${colors.bgYellow}${colors.bold} BETA ${colors.reset} ${colors.yellow}This feature is in beta and not yet stable${colors.reset}`
19
- );
20
- console.log(`${colors.dim} Expect bugs and incomplete features${colors.reset}`);
21
- console.log('');
22
- }
23
-
24
- function showHeader() {
25
- console.log(`${colors.orange}${colors.bold}`);
26
- console.log(' ╔═══════════════════════════════════════════╗');
27
- console.log(' ║ AgileFlow TUI Dashboard ║');
28
- console.log(' ╚═══════════════════════════════════════════╝');
29
- console.log(`${colors.reset}`);
30
- }
31
-
32
- async function loadStatus() {
33
- const statusPath = path.join(process.cwd(), 'docs', '09-agents', 'status.json');
34
-
35
- if (!fs.existsSync(statusPath)) {
36
- return null;
37
- }
38
-
39
- try {
40
- const content = fs.readFileSync(statusPath, 'utf8');
41
- return JSON.parse(content);
42
- } catch (err) {
43
- return null;
44
- }
45
- }
46
-
47
- function getStatusColor(status) {
48
- switch (status) {
49
- case 'completed':
50
- case 'done':
51
- return colors.green;
52
- case 'in_progress':
53
- case 'in-progress':
54
- return colors.yellow;
55
- case 'blocked':
56
- return colors.red;
57
- case 'ready':
58
- return colors.cyan;
59
- default:
60
- return colors.dim;
61
- }
62
- }
63
-
64
- function formatStory(story) {
65
- const statusColor = getStatusColor(story.status);
66
- const id = story.id || story.story_id || 'Unknown';
67
- const title = story.title || story.summary || 'Untitled';
68
- const status = (story.status || 'unknown').toUpperCase();
69
- const owner = story.owner || '-';
70
-
71
- return ` ${colors.bold}${id}${colors.reset} ${title.substring(0, 40)}${title.length > 40 ? '...' : ''}
72
- ${statusColor}[${status}]${colors.reset} ${colors.dim}Owner: ${owner}${colors.reset}`;
73
- }
74
-
75
- async function showDashboard() {
76
- showBetaWarning();
77
- showHeader();
78
-
79
- const status = await loadStatus();
80
-
81
- if (!status) {
82
- console.log(
83
- `${colors.dim} No status.json found. Run /agileflow:story to create stories.${colors.reset}`
84
- );
85
- console.log('');
86
- return;
87
- }
88
-
89
- // Count stories by status
90
- const stories = Object.values(status).filter(
91
- s => s && typeof s === 'object' && (s.id || s.story_id)
92
- );
93
- const counts = {
94
- in_progress: stories.filter(s => ['in_progress', 'in-progress'].includes(s.status)).length,
95
- blocked: stories.filter(s => s.status === 'blocked').length,
96
- ready: stories.filter(s => s.status === 'ready').length,
97
- completed: stories.filter(s => ['completed', 'done'].includes(s.status)).length,
98
- };
99
-
100
- const total = stories.length;
101
- const completionPct = total > 0 ? Math.round((counts.completed / total) * 100) : 0;
102
-
103
- // Summary
104
- console.log(`${colors.bold} Summary${colors.reset}`);
105
- console.log(` ────────────────────────────────────────────`);
106
- console.log(
107
- ` ${colors.yellow}In Progress:${colors.reset} ${counts.in_progress} ${colors.red}Blocked:${colors.reset} ${counts.blocked} ${colors.cyan}Ready:${colors.reset} ${counts.ready} ${colors.green}Done:${colors.reset} ${counts.completed}`
108
- );
109
- console.log(` ${colors.dim}Completion: ${completionPct}%${colors.reset}`);
110
- console.log('');
111
-
112
- // In Progress Stories
113
- const inProgressStories = stories.filter(s => ['in_progress', 'in-progress'].includes(s.status));
114
- if (inProgressStories.length > 0) {
115
- console.log(`${colors.bold} ${colors.yellow}In Progress${colors.reset}`);
116
- console.log(` ────────────────────────────────────────────`);
117
- inProgressStories.forEach(story => {
118
- console.log(formatStory(story));
119
- });
120
- console.log('');
121
- }
122
-
123
- // Blocked Stories
124
- const blockedStories = stories.filter(s => s.status === 'blocked');
125
- if (blockedStories.length > 0) {
126
- console.log(`${colors.bold} ${colors.red}Blocked${colors.reset}`);
127
- console.log(` ────────────────────────────────────────────`);
128
- blockedStories.forEach(story => {
129
- console.log(formatStory(story));
130
- });
131
- console.log('');
132
- }
133
-
134
- // Ready Stories (up to 5)
135
- const readyStories = stories.filter(s => s.status === 'ready').slice(0, 5);
136
- if (readyStories.length > 0) {
137
- console.log(
138
- `${colors.bold} ${colors.cyan}Ready for Work${colors.reset} ${colors.dim}(showing ${readyStories.length} of ${counts.ready})${colors.reset}`
139
- );
140
- console.log(` ────────────────────────────────────────────`);
141
- readyStories.forEach(story => {
142
- console.log(formatStory(story));
143
- });
144
- console.log('');
145
- }
146
-
147
- console.log(`${colors.dim} Use /agileflow:board for interactive kanban view${colors.reset}`);
148
- console.log(`${colors.dim} Use /agileflow:story:list for full story list${colors.reset}`);
149
- console.log('');
150
- }
151
-
152
- async function main() {
153
- const args = process.argv.slice(2);
154
-
155
- // Check for help flag
156
- if (args.includes('--help') || args.includes('-h')) {
157
- showBetaWarning();
158
- console.log(`${colors.bold}AgileFlow TUI Dashboard${colors.reset}`);
159
- console.log('');
160
- console.log(`${colors.bold}Usage:${colors.reset}`);
161
- console.log(' npx agileflow start Show dashboard');
162
- console.log(' npx agileflow start --help Show this help');
163
- console.log('');
164
- console.log(
165
- `${colors.dim}This is a beta feature. For stable commands, use Claude Code slash commands.${colors.reset}`
166
- );
167
- return;
168
- }
169
-
170
- await showDashboard();
171
- }
172
-
173
- main().catch(err => {
174
- console.error(`${colors.red}Error:${colors.reset}`, err.message);
175
- process.exit(1);
176
- });
177
-
178
- module.exports = { main };
@@ -1,65 +0,0 @@
1
- /**
2
- * Dashboard Component
3
- *
4
- * BETA - Main TUI dashboard view
5
- */
6
-
7
- const path = require('path');
8
- const fs = require('fs');
9
-
10
- class Dashboard {
11
- constructor(options = {}) {
12
- this.statusPath =
13
- options.statusPath || path.join(process.cwd(), 'docs', '09-agents', 'status.json');
14
- this.data = null;
15
- }
16
-
17
- async load() {
18
- if (!fs.existsSync(this.statusPath)) {
19
- return false;
20
- }
21
-
22
- try {
23
- const content = fs.readFileSync(this.statusPath, 'utf8');
24
- this.data = JSON.parse(content);
25
- return true;
26
- } catch (err) {
27
- return false;
28
- }
29
- }
30
-
31
- getStories() {
32
- if (!this.data) return [];
33
- return Object.values(this.data).filter(s => s && typeof s === 'object' && (s.id || s.story_id));
34
- }
35
-
36
- getStats() {
37
- const stories = this.getStories();
38
- return {
39
- total: stories.length,
40
- in_progress: stories.filter(s => ['in_progress', 'in-progress'].includes(s.status)).length,
41
- blocked: stories.filter(s => s.status === 'blocked').length,
42
- ready: stories.filter(s => s.status === 'ready').length,
43
- completed: stories.filter(s => ['completed', 'done'].includes(s.status)).length,
44
- };
45
- }
46
-
47
- getCompletionPercentage() {
48
- const stats = this.getStats();
49
- if (stats.total === 0) return 0;
50
- return Math.round((stats.completed / stats.total) * 100);
51
- }
52
-
53
- getStoriesByStatus(status) {
54
- const stories = this.getStories();
55
- if (status === 'in_progress') {
56
- return stories.filter(s => ['in_progress', 'in-progress'].includes(s.status));
57
- }
58
- if (status === 'completed') {
59
- return stories.filter(s => ['completed', 'done'].includes(s.status));
60
- }
61
- return stories.filter(s => s.status === status);
62
- }
63
- }
64
-
65
- module.exports = Dashboard;
@@ -1,69 +0,0 @@
1
- /**
2
- * StoryList Component
3
- *
4
- * BETA - Story list rendering for TUI
5
- */
6
-
7
- class StoryList {
8
- constructor(stories = []) {
9
- this.stories = stories;
10
- this.selectedIndex = 0;
11
- }
12
-
13
- setStories(stories) {
14
- this.stories = stories;
15
- this.selectedIndex = 0;
16
- }
17
-
18
- selectNext() {
19
- if (this.selectedIndex < this.stories.length - 1) {
20
- this.selectedIndex++;
21
- }
22
- return this.getSelected();
23
- }
24
-
25
- selectPrev() {
26
- if (this.selectedIndex > 0) {
27
- this.selectedIndex--;
28
- }
29
- return this.getSelected();
30
- }
31
-
32
- getSelected() {
33
- return this.stories[this.selectedIndex] || null;
34
- }
35
-
36
- filter(predicate) {
37
- return new StoryList(this.stories.filter(predicate));
38
- }
39
-
40
- sortByPriority() {
41
- const priorityOrder = {
42
- blocked: 0,
43
- in_progress: 1,
44
- 'in-progress': 1,
45
- ready: 2,
46
- draft: 3,
47
- completed: 4,
48
- done: 4,
49
- };
50
-
51
- return new StoryList(
52
- [...this.stories].sort((a, b) => {
53
- const aPriority = priorityOrder[a.status] ?? 99;
54
- const bPriority = priorityOrder[b.status] ?? 99;
55
- return aPriority - bPriority;
56
- })
57
- );
58
- }
59
-
60
- toArray() {
61
- return [...this.stories];
62
- }
63
-
64
- get length() {
65
- return this.stories.length;
66
- }
67
- }
68
-
69
- module.exports = StoryList;
@@ -1,16 +0,0 @@
1
- /**
2
- * AgileFlow TUI Components
3
- *
4
- * BETA - Internal use only, not publicly documented
5
- *
6
- * This module contains TUI components for the AgileFlow dashboard.
7
- * Currently in early development.
8
- */
9
-
10
- const Dashboard = require('./Dashboard');
11
- const StoryList = require('./StoryList');
12
-
13
- module.exports = {
14
- Dashboard,
15
- StoryList,
16
- };