wogiflow 1.0.22 → 1.0.24
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/commands/wogi-capture.md +57 -0
- package/.claude/commands/wogi-compact.md +23 -1
- package/.claude/commands/wogi-correction.md +45 -0
- package/.claude/commands/wogi-init.md +0 -3
- package/.claude/commands/wogi-peer-review.md +164 -0
- package/.claude/commands/wogi-start.md +41 -0
- package/package.json +1 -1
- package/scripts/flow +10 -0
- package/scripts/flow-capture.js +246 -0
- package/scripts/flow-clarifying-questions.js +412 -0
- package/scripts/flow-correct.js +147 -1
- package/scripts/flow-memory-blocks.js +51 -0
- package/scripts/flow-model-caller.js +332 -0
- package/scripts/flow-peer-review.js +512 -0
- package/scripts/flow-start.js +29 -0
- package/scripts/flow-utils.js +36 -0
- package/scripts/hooks/core/session-context.js +53 -0
- package/scripts/postinstall.js +65 -3
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Quick capture an idea or bug without interrupting your current work. Provide a brief title: `/wogi-capture Add dark mode toggle`
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
/wogi-capture "Your idea or bug here"
|
|
7
|
+
/wogi-capture "Bug: login fails on Safari"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Just provide a brief title. That's it.
|
|
11
|
+
|
|
12
|
+
## What Happens
|
|
13
|
+
|
|
14
|
+
1. **Auto-detect type** from keywords:
|
|
15
|
+
- "bug", "fix", "broken", "error", "crash", "fails" → `bug`
|
|
16
|
+
- Everything else → `feature`
|
|
17
|
+
|
|
18
|
+
2. **Auto-tag** from current context (if a task is in progress)
|
|
19
|
+
|
|
20
|
+
3. **Add to backlog** in `ready.json` with minimal metadata
|
|
21
|
+
|
|
22
|
+
4. **Minimal confirmation** - just "Captured: [title]"
|
|
23
|
+
|
|
24
|
+
## Backlog Triage
|
|
25
|
+
|
|
26
|
+
Items go to a `backlog` array in ready.json. Use `/wogi-ready` to see them.
|
|
27
|
+
|
|
28
|
+
Later you can:
|
|
29
|
+
- Promote to `ready` (use `/wogi-story` to create proper story)
|
|
30
|
+
- Discard if no longer relevant
|
|
31
|
+
- Convert to bug with `/wogi-bug`
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
/wogi-capture Add export to PDF
|
|
37
|
+
→ Captured: Add export to PDF (feature)
|
|
38
|
+
|
|
39
|
+
/wogi-capture Bug: form validation not working
|
|
40
|
+
→ Captured: Bug: form validation not working (bug)
|
|
41
|
+
|
|
42
|
+
/wogi-capture Broken image on profile page
|
|
43
|
+
→ Captured: Broken image on profile page (bug)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## CLI Usage
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node scripts/flow-capture.js "Add dark mode toggle"
|
|
50
|
+
node scripts/flow-capture.js "Bug: login fails" --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Options
|
|
54
|
+
|
|
55
|
+
- `--type <type>` - Force type (bug/feature) instead of auto-detect
|
|
56
|
+
- `--tags <tags>` - Add comma-separated tags
|
|
57
|
+
- `--json` - Output JSON instead of minimal confirmation
|
|
@@ -15,6 +15,21 @@ Root (overview)
|
|
|
15
15
|
└── File changes (expandable)
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
## CRITICAL: Task Queue Check
|
|
19
|
+
|
|
20
|
+
**Before ANY compaction**, you MUST:
|
|
21
|
+
|
|
22
|
+
1. Read `.workflow/state/ready.json`
|
|
23
|
+
2. Note pending tasks in your summary
|
|
24
|
+
3. **NEVER claim "nothing pending" without checking ready.json**
|
|
25
|
+
|
|
26
|
+
If tasks exist:
|
|
27
|
+
- **In Progress**: List task IDs currently being worked on
|
|
28
|
+
- **Ready**: Count + list task IDs awaiting work
|
|
29
|
+
- **Blocked**: Count blocked tasks
|
|
30
|
+
|
|
31
|
+
This ensures task awareness survives context compaction.
|
|
32
|
+
|
|
18
33
|
## Before Compacting
|
|
19
34
|
|
|
20
35
|
1. **Update progress.md** with:
|
|
@@ -48,7 +63,12 @@ Provide this information for the compaction system:
|
|
|
48
63
|
- [Task/change 1]
|
|
49
64
|
- [Task/change 2]
|
|
50
65
|
|
|
51
|
-
**
|
|
66
|
+
**Pending Tasks** (REQUIRED - from ready.json):
|
|
67
|
+
- In Progress: [task IDs or "none"]
|
|
68
|
+
- Ready: [count] tasks - [first 5 task IDs]
|
|
69
|
+
- Blocked: [count] tasks
|
|
70
|
+
|
|
71
|
+
**In Progress (Current)**:
|
|
52
72
|
- TASK-XXX: [description] - [current state, what's left]
|
|
53
73
|
|
|
54
74
|
**Key Decisions**:
|
|
@@ -65,6 +85,8 @@ Provide this information for the compaction system:
|
|
|
65
85
|
|
|
66
86
|
**Context to Preserve**:
|
|
67
87
|
- [Important context that should survive compaction]
|
|
88
|
+
|
|
89
|
+
**ON RESUME**: Check `.workflow/state/ready.json` for pending work.
|
|
68
90
|
```
|
|
69
91
|
|
|
70
92
|
## Context Pressure Monitoring
|
|
@@ -9,6 +9,51 @@ Based on `config.json` corrections mode:
|
|
|
9
9
|
- **hybrid**: Use for significant/complex fixes
|
|
10
10
|
- **always-detailed**: Use for every fix
|
|
11
11
|
|
|
12
|
+
## Auto-Triggered Corrections (NEW)
|
|
13
|
+
|
|
14
|
+
Corrections can be automatically prompted when failures are detected:
|
|
15
|
+
|
|
16
|
+
**Trigger Points:**
|
|
17
|
+
- Lint/TypeScript failures after file edit
|
|
18
|
+
- Test failures after implementation
|
|
19
|
+
- Critical review findings (severity "critical")
|
|
20
|
+
- Repeated tech debt (3+ occurrences)
|
|
21
|
+
|
|
22
|
+
**When triggered, you'll see:**
|
|
23
|
+
```
|
|
24
|
+
⚠️ TypeScript error detected:
|
|
25
|
+
Property 'x' does not exist on type 'Y'
|
|
26
|
+
|
|
27
|
+
Would you like to record this as a correction for future learning?
|
|
28
|
+
This helps avoid similar mistakes.
|
|
29
|
+
|
|
30
|
+
[Yes, record correction] [No, skip]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**If user selects Yes:**
|
|
34
|
+
1. Create correction file with pre-filled context
|
|
35
|
+
2. Update feedback-patterns.md with pattern count
|
|
36
|
+
3. If pattern count >= 3, prompt for promotion to decisions.md
|
|
37
|
+
|
|
38
|
+
**API for scripts:**
|
|
39
|
+
```javascript
|
|
40
|
+
const { promptForCorrection, createAutoCorrection } = require('./flow-correct');
|
|
41
|
+
|
|
42
|
+
// Check if should prompt
|
|
43
|
+
const prompt = promptForCorrection({
|
|
44
|
+
type: 'typecheck',
|
|
45
|
+
error: 'Property x does not exist',
|
|
46
|
+
files: ['src/api.ts'],
|
|
47
|
+
taskId: 'wf-abc123'
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (prompt.shouldPrompt) {
|
|
51
|
+
// Ask user via AskUserQuestion
|
|
52
|
+
// If yes, create correction:
|
|
53
|
+
createAutoCorrection(prompt.correctionData);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
12
57
|
## Steps
|
|
13
58
|
|
|
14
59
|
1. Read `config.json` to check corrections mode
|
|
@@ -509,9 +509,6 @@ This file tracks all changes made to the project.
|
|
|
509
509
|
**Files**: .workflow/*, .claude/*
|
|
510
510
|
```
|
|
511
511
|
|
|
512
|
-
**roadmap.md** (future work):
|
|
513
|
-
Copy from `templates/roadmap.md` to `.workflow/roadmap.md`
|
|
514
|
-
|
|
515
512
|
#### 4.4 Create Spec Files
|
|
516
513
|
|
|
517
514
|
**stack.md** in `.workflow/specs/`:
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Run a multi-model peer review where different AI models review the same code.
|
|
2
|
+
|
|
3
|
+
## How It Works
|
|
4
|
+
|
|
5
|
+
1. **Primary model (Claude)** reviews the changes for improvements
|
|
6
|
+
2. **Secondary model(s)** review the same changes
|
|
7
|
+
3. **Findings are compared** and disagreements surfaced
|
|
8
|
+
4. **Primary model responds** to peer feedback:
|
|
9
|
+
- Defends decisions with context
|
|
10
|
+
- OR acknowledges valid alternatives
|
|
11
|
+
|
|
12
|
+
## Key Difference from `/wogi-review`
|
|
13
|
+
|
|
14
|
+
| `/wogi-review` | `/wogi-peer-review` |
|
|
15
|
+
|----------------|---------------------|
|
|
16
|
+
| "Is this correct, secure, working?" | "Is this the BEST approach?" |
|
|
17
|
+
| Bug detection | Optimization opportunities |
|
|
18
|
+
| Security vulnerabilities | Alternative implementations |
|
|
19
|
+
| Architecture conflicts | Pattern suggestions |
|
|
20
|
+
| Verification-focused | Improvement-focused |
|
|
21
|
+
|
|
22
|
+
## What Peer Review Surfaces
|
|
23
|
+
|
|
24
|
+
1. **Optimization opportunities** - "This works, but could be faster/cleaner"
|
|
25
|
+
2. **Alternative approaches** - "Consider doing X instead of Y"
|
|
26
|
+
3. **Cross-model disagreements** - Where different models see things differently
|
|
27
|
+
4. **Pattern suggestions** - "Other codebases typically do this as..."
|
|
28
|
+
5. **Missed edge cases** - Fresh eyes catch what familiarity misses
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
/wogi-peer-review # Review staged changes
|
|
34
|
+
/wogi-peer-review --files src/*.ts # Review specific files
|
|
35
|
+
/wogi-peer-review --task wf-abc123 # Review task changes
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Provider Configuration
|
|
39
|
+
|
|
40
|
+
Configure in `.workflow/config.json` under `peerReview`:
|
|
41
|
+
|
|
42
|
+
### Option A: API Keys (Default)
|
|
43
|
+
```json
|
|
44
|
+
"peerReview": {
|
|
45
|
+
"enabled": true,
|
|
46
|
+
"provider": "api",
|
|
47
|
+
"models": ["openai:gpt-4o", "google:gemini-pro"],
|
|
48
|
+
"apiKeys": {
|
|
49
|
+
"openai": "${OPENAI_API_KEY}",
|
|
50
|
+
"google": "${GOOGLE_API_KEY}"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Option B: MCP Integration
|
|
56
|
+
```json
|
|
57
|
+
"peerReview": {
|
|
58
|
+
"enabled": true,
|
|
59
|
+
"provider": "mcp",
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"openai": "mcp-openai",
|
|
62
|
+
"google": "mcp-gemini"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Option C: Manual Mode
|
|
68
|
+
```json
|
|
69
|
+
"peerReview": {
|
|
70
|
+
"enabled": true,
|
|
71
|
+
"provider": "manual"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
When manual:
|
|
76
|
+
1. Outputs the review prompt
|
|
77
|
+
2. User runs in Cursor/other tool
|
|
78
|
+
3. User pastes results back
|
|
79
|
+
4. Claude synthesizes
|
|
80
|
+
|
|
81
|
+
## Review Flow
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
┌─────────────────────────────────────────────────────────┐
|
|
85
|
+
│ /wogi-peer-review │
|
|
86
|
+
├─────────────────────────────────────────────────────────┤
|
|
87
|
+
│ 1. Collect code changes (git diff or specified files) │
|
|
88
|
+
│ 2. Generate improvement-focused prompt │
|
|
89
|
+
│ 3. Claude reviews for improvements │
|
|
90
|
+
│ 4. Secondary model(s) review │
|
|
91
|
+
│ 5. Compare findings: │
|
|
92
|
+
│ • Both agree → Strong suggestion │
|
|
93
|
+
│ • Disagree → Present both perspectives │
|
|
94
|
+
│ 6. Claude responds to peer feedback: │
|
|
95
|
+
│ • "I have more context, here's why X is better..." │
|
|
96
|
+
│ • "Valid point, Y would be an improvement..." │
|
|
97
|
+
│ 7. Output final synthesis │
|
|
98
|
+
└─────────────────────────────────────────────────────────┘
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Review Prompt Template
|
|
102
|
+
|
|
103
|
+
The peer review focuses on improvements, not correctness:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
Review this code for IMPROVEMENT OPPORTUNITIES, not bugs:
|
|
107
|
+
|
|
108
|
+
1. **Optimization**: Can this be faster/more efficient?
|
|
109
|
+
2. **Alternatives**: Are there better approaches?
|
|
110
|
+
3. **Patterns**: Does this follow best practices?
|
|
111
|
+
4. **Readability**: Could this be clearer/simpler?
|
|
112
|
+
5. **Extensibility**: Will this be easy to extend?
|
|
113
|
+
|
|
114
|
+
Code:
|
|
115
|
+
[code changes]
|
|
116
|
+
|
|
117
|
+
Respond with:
|
|
118
|
+
- Specific improvement suggestions
|
|
119
|
+
- Alternative approaches considered
|
|
120
|
+
- Trade-off analysis for any changes
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Output
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
127
|
+
🔍 Peer Review Results
|
|
128
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
129
|
+
|
|
130
|
+
✅ Agreement (2/2 models):
|
|
131
|
+
• Consider using early return for readability
|
|
132
|
+
• Extract repeated logic to helper function
|
|
133
|
+
|
|
134
|
+
⚖️ Disagreement:
|
|
135
|
+
• Claude: Prefer inline styling for this case
|
|
136
|
+
• GPT-4: Recommend extracting to CSS module
|
|
137
|
+
→ Resolution: Context-dependent, current approach is valid
|
|
138
|
+
|
|
139
|
+
💡 Unique Insights:
|
|
140
|
+
• [GPT-4] Consider memoization for expensive computation
|
|
141
|
+
• [Claude] Current architecture handles edge case X well
|
|
142
|
+
|
|
143
|
+
📊 Summary:
|
|
144
|
+
3 actionable improvements identified
|
|
145
|
+
1 disagreement resolved
|
|
146
|
+
Code quality: Good, with minor optimization opportunities
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## When to Use
|
|
150
|
+
|
|
151
|
+
- Before merging significant changes
|
|
152
|
+
- For security-sensitive code
|
|
153
|
+
- When you want high confidence
|
|
154
|
+
- For learning different perspectives
|
|
155
|
+
- When stuck on architecture decisions
|
|
156
|
+
|
|
157
|
+
## Options
|
|
158
|
+
|
|
159
|
+
- `--provider <name>` - Override configured provider
|
|
160
|
+
- `--model <name>` - Specify secondary model
|
|
161
|
+
- `--files <glob>` - Review specific files
|
|
162
|
+
- `--task <id>` - Review task changes
|
|
163
|
+
- `--json` - Output JSON for automation
|
|
164
|
+
- `--verbose` - Show full model responses
|
|
@@ -96,6 +96,47 @@ This command implements a **structured execution loop**:
|
|
|
96
96
|
5. Check `.workflow/state/app-map.md` for components mentioned
|
|
97
97
|
6. Check `.workflow/state/decisions.md` for relevant patterns
|
|
98
98
|
7. **Auto-invoke skills** based on task context:
|
|
99
|
+
|
|
100
|
+
### Step 1.2: Clarifying Questions (NEW)
|
|
101
|
+
|
|
102
|
+
**BEFORE generating specifications**, ask clarifying questions to catch assumptions early:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
106
|
+
❓ Clarifying Questions
|
|
107
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
108
|
+
Before implementation, consider clarifying:
|
|
109
|
+
|
|
110
|
+
🎯 Scope Validation
|
|
111
|
+
1. Found X related files. Should I modify all of them?
|
|
112
|
+
|
|
113
|
+
💡 Assumption Surfacing
|
|
114
|
+
2. Should I assume [pattern] for this task?
|
|
115
|
+
|
|
116
|
+
🔀 Edge Cases
|
|
117
|
+
3. What should happen when [error condition]?
|
|
118
|
+
|
|
119
|
+
Note: You can proceed without answering, but clarification may prevent rework.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Question Categories:**
|
|
123
|
+
- **Scope Validation**: "Found X components. Are we changing all?"
|
|
124
|
+
- **Assumption Surfacing**: "Should I assume [pattern] for this task?"
|
|
125
|
+
- **Edge Cases**: "What about [similar scenario]?"
|
|
126
|
+
- **Integration Points**: "This touches [component]. Dependency concerns?"
|
|
127
|
+
- **Implementation Preferences**: "Any specific approach you prefer?"
|
|
128
|
+
|
|
129
|
+
**Config**: Controlled by `config.clarifyingQuestions`:
|
|
130
|
+
- `enabled`: true/false
|
|
131
|
+
- `maxQuestions`: max questions to ask (default: 5)
|
|
132
|
+
- `skipForSmallTasks`: skip for small tasks (default: true)
|
|
133
|
+
- `smallTaskThreshold`: files count threshold (default: 2)
|
|
134
|
+
|
|
135
|
+
**Skipped for**: Small tasks (≤2 files), bugfixes, tasks with explicit specs
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
**Skill Matching Output:**
|
|
99
140
|
- Run skill matcher against task description
|
|
100
141
|
- Load matched skills (patterns.md, anti-patterns.md, learnings.md)
|
|
101
142
|
- Display matched skills with scores
|
package/package.json
CHANGED
package/scripts/flow
CHANGED
|
@@ -56,6 +56,7 @@ show_help() {
|
|
|
56
56
|
echo " story <title> --deep Create story with automatic decomposition"
|
|
57
57
|
echo " new-feature <n> Create new feature"
|
|
58
58
|
echo " bug <title> Create bug report"
|
|
59
|
+
echo " capture <title> Quick capture idea/bug without interrupting flow"
|
|
59
60
|
echo ""
|
|
60
61
|
echo "Roadmap & Planning:"
|
|
61
62
|
echo " roadmap Show project roadmap"
|
|
@@ -363,6 +364,9 @@ case "${1:-}" in
|
|
|
363
364
|
bug)
|
|
364
365
|
node "$SCRIPT_DIR/flow-bug.js" "${@:2}"
|
|
365
366
|
;;
|
|
367
|
+
capture)
|
|
368
|
+
node "$SCRIPT_DIR/flow-capture.js" "${@:2}"
|
|
369
|
+
;;
|
|
366
370
|
status)
|
|
367
371
|
node "$SCRIPT_DIR/flow-status.js" "${@:2}"
|
|
368
372
|
;;
|
|
@@ -471,6 +475,9 @@ case "${1:-}" in
|
|
|
471
475
|
review)
|
|
472
476
|
node "$SCRIPT_DIR/flow-review.js" "${@:2}"
|
|
473
477
|
;;
|
|
478
|
+
peer-review)
|
|
479
|
+
node "$SCRIPT_DIR/flow-peer-review.js" "${@:2}"
|
|
480
|
+
;;
|
|
474
481
|
correct)
|
|
475
482
|
node "$SCRIPT_DIR/flow-correct.js" "${@:2}"
|
|
476
483
|
;;
|
|
@@ -489,6 +496,9 @@ case "${1:-}" in
|
|
|
489
496
|
context)
|
|
490
497
|
"$SCRIPT_DIR/flow-context" "${@:2}"
|
|
491
498
|
;;
|
|
499
|
+
clarifying-questions|clarify)
|
|
500
|
+
node "$SCRIPT_DIR/flow-clarifying-questions.js" "${@:2}"
|
|
501
|
+
;;
|
|
492
502
|
links)
|
|
493
503
|
node "$SCRIPT_DIR/flow-links.js" "${@:2}"
|
|
494
504
|
;;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Quick Capture
|
|
5
|
+
*
|
|
6
|
+
* Quickly capture ideas or bugs without interrupting flow.
|
|
7
|
+
* Items go to backlog in ready.json for later triage.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node scripts/flow-capture.js "<title>" [--type bug|feature] [--tags tag1,tag2] [--json]
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const {
|
|
15
|
+
PATHS,
|
|
16
|
+
readJson,
|
|
17
|
+
writeJson,
|
|
18
|
+
parseFlags,
|
|
19
|
+
outputJson,
|
|
20
|
+
success,
|
|
21
|
+
error
|
|
22
|
+
} = require('./flow-utils');
|
|
23
|
+
|
|
24
|
+
// Try to load session state for auto-detecting current task
|
|
25
|
+
let loadSessionState;
|
|
26
|
+
try {
|
|
27
|
+
const sessionModule = require('./flow-session-state');
|
|
28
|
+
loadSessionState = sessionModule.loadSessionState;
|
|
29
|
+
} catch (importError) {
|
|
30
|
+
if (process.env.DEBUG) {
|
|
31
|
+
console.warn(`[DEBUG] Could not load flow-session-state: ${importError.message}`);
|
|
32
|
+
}
|
|
33
|
+
loadSessionState = () => ({});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Keywords that indicate a bug report
|
|
38
|
+
*/
|
|
39
|
+
const BUG_KEYWORDS = [
|
|
40
|
+
'bug',
|
|
41
|
+
'fix',
|
|
42
|
+
'broken',
|
|
43
|
+
'error',
|
|
44
|
+
'crash',
|
|
45
|
+
'fails',
|
|
46
|
+
'failing',
|
|
47
|
+
'not working',
|
|
48
|
+
'doesn\'t work',
|
|
49
|
+
'issue',
|
|
50
|
+
'problem'
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Auto-detect type from title
|
|
55
|
+
* @param {string} title - The captured title
|
|
56
|
+
* @returns {'bug' | 'feature'}
|
|
57
|
+
*/
|
|
58
|
+
function detectType(title) {
|
|
59
|
+
const lowerTitle = title.toLowerCase();
|
|
60
|
+
|
|
61
|
+
for (const keyword of BUG_KEYWORDS) {
|
|
62
|
+
if (lowerTitle.includes(keyword)) {
|
|
63
|
+
return 'bug';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return 'feature';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Generate a capture ID
|
|
72
|
+
* Format: cap-YYYYMMDD-NNN
|
|
73
|
+
* @param {Array} existingBacklog - Existing backlog items
|
|
74
|
+
* @returns {string}
|
|
75
|
+
*/
|
|
76
|
+
function generateCaptureId(existingBacklog) {
|
|
77
|
+
const today = new Date().toISOString().split('T')[0].replace(/-/g, '');
|
|
78
|
+
|
|
79
|
+
// Find highest number for today
|
|
80
|
+
const todayPattern = new RegExp(`^cap-${today}-(\\d{3})$`);
|
|
81
|
+
let maxNum = 0;
|
|
82
|
+
|
|
83
|
+
for (const item of existingBacklog) {
|
|
84
|
+
const match = item.id && item.id.match(todayPattern);
|
|
85
|
+
if (match) {
|
|
86
|
+
maxNum = Math.max(maxNum, parseInt(match[1], 10));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const nextNum = String(maxNum + 1).padStart(3, '0');
|
|
91
|
+
return `cap-${today}-${nextNum}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get current task from session state
|
|
96
|
+
*/
|
|
97
|
+
function getCurrentTask() {
|
|
98
|
+
try {
|
|
99
|
+
const sessionState = loadSessionState();
|
|
100
|
+
return sessionState.currentTask || null;
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Extract tags from current task context
|
|
108
|
+
* @param {Object|null} currentTask - Current task if any
|
|
109
|
+
* @returns {string[]}
|
|
110
|
+
*/
|
|
111
|
+
function extractContextTags(currentTask) {
|
|
112
|
+
if (!currentTask) return [];
|
|
113
|
+
|
|
114
|
+
const tags = [];
|
|
115
|
+
|
|
116
|
+
if (currentTask.feature) {
|
|
117
|
+
tags.push(`#feature:${currentTask.feature}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Could also extract #screen: or #component: from task description
|
|
121
|
+
// if task has tags field
|
|
122
|
+
if (currentTask.tags && Array.isArray(currentTask.tags)) {
|
|
123
|
+
tags.push(...currentTask.tags);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return tags;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Add item to backlog in ready.json
|
|
131
|
+
* @param {Object} item - Backlog item to add
|
|
132
|
+
*/
|
|
133
|
+
function addToBacklog(item) {
|
|
134
|
+
const readyPath = PATHS.ready;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const ready = readJson(readyPath, {
|
|
138
|
+
lastUpdated: new Date().toISOString(),
|
|
139
|
+
ready: [],
|
|
140
|
+
inProgress: [],
|
|
141
|
+
blocked: [],
|
|
142
|
+
recentlyCompleted: [],
|
|
143
|
+
backlog: []
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Ensure backlog is an array (not just non-null)
|
|
147
|
+
if (!Array.isArray(ready.backlog)) {
|
|
148
|
+
ready.backlog = [];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Add item
|
|
152
|
+
ready.backlog.push(item);
|
|
153
|
+
ready.lastUpdated = new Date().toISOString();
|
|
154
|
+
|
|
155
|
+
// Write back
|
|
156
|
+
writeJson(readyPath, ready);
|
|
157
|
+
} catch (err) {
|
|
158
|
+
error(`Failed to add to backlog: ${err.message}`);
|
|
159
|
+
throw err;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Main function
|
|
165
|
+
*/
|
|
166
|
+
function main() {
|
|
167
|
+
const { flags, positional } = parseFlags(process.argv.slice(2));
|
|
168
|
+
|
|
169
|
+
// Handle help
|
|
170
|
+
if (flags.help) {
|
|
171
|
+
console.log(`
|
|
172
|
+
Usage: flow capture "<title>" [options]
|
|
173
|
+
|
|
174
|
+
Quick capture an idea or bug without interrupting flow.
|
|
175
|
+
|
|
176
|
+
Options:
|
|
177
|
+
--type <type> Force type: bug or feature (default: auto-detect)
|
|
178
|
+
--tags <tags> Comma-separated tags to add
|
|
179
|
+
--json Output JSON
|
|
180
|
+
|
|
181
|
+
Examples:
|
|
182
|
+
flow capture "Add dark mode toggle"
|
|
183
|
+
flow capture "Bug: login fails on Safari"
|
|
184
|
+
flow capture "Fix broken image" --type bug --tags "#screen:profile"
|
|
185
|
+
`);
|
|
186
|
+
process.exit(0);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Validate title
|
|
190
|
+
const title = positional[0];
|
|
191
|
+
if (!title) {
|
|
192
|
+
error('Title is required');
|
|
193
|
+
console.log('Usage: flow capture "<title>"');
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Get current task for context
|
|
198
|
+
const currentTask = getCurrentTask();
|
|
199
|
+
|
|
200
|
+
// Load existing backlog to generate ID
|
|
201
|
+
const ready = readJson(PATHS.ready, { backlog: [] });
|
|
202
|
+
const existingBacklog = ready.backlog || [];
|
|
203
|
+
|
|
204
|
+
// Generate ID
|
|
205
|
+
const id = generateCaptureId(existingBacklog);
|
|
206
|
+
|
|
207
|
+
// Determine type
|
|
208
|
+
const type = flags.type || detectType(title);
|
|
209
|
+
|
|
210
|
+
// Gather tags
|
|
211
|
+
let tags = extractContextTags(currentTask);
|
|
212
|
+
if (flags.tags) {
|
|
213
|
+
const userTags = flags.tags.split(',').map(t => t.trim()).filter(Boolean);
|
|
214
|
+
tags = [...tags, ...userTags];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Create capture item
|
|
218
|
+
const item = {
|
|
219
|
+
id,
|
|
220
|
+
title,
|
|
221
|
+
type,
|
|
222
|
+
capturedAt: new Date().toISOString(),
|
|
223
|
+
...(currentTask && { capturedDuring: currentTask.id }),
|
|
224
|
+
...(tags.length > 0 && { tags })
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// Add to backlog
|
|
228
|
+
addToBacklog(item);
|
|
229
|
+
|
|
230
|
+
// Output
|
|
231
|
+
if (flags.json) {
|
|
232
|
+
outputJson({
|
|
233
|
+
success: true,
|
|
234
|
+
captured: item
|
|
235
|
+
});
|
|
236
|
+
} else {
|
|
237
|
+
success(`Captured: ${title} (${type})`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Run only when executed directly
|
|
242
|
+
if (require.main === module) {
|
|
243
|
+
main();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
module.exports = { main, detectType, generateCaptureId, addToBacklog };
|