wogiflow 1.5.5 → 1.5.7

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.
@@ -0,0 +1,60 @@
1
+ # Project Rules
2
+
3
+ This directory contains coding rules and patterns for this project, organized by category.
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ .claude/rules/
9
+ ├── code-style/ # Naming conventions, formatting
10
+ │ └── naming-conventions.md
11
+ ├── security/ # Security patterns and practices
12
+ │ └── security-patterns.md
13
+ ├── architecture/ # Design decisions and patterns
14
+ │ ├── component-reuse.md
15
+ │ └── model-management.md
16
+ └── README.md
17
+ ```
18
+
19
+ ## How Rules Work
20
+
21
+ Rules are automatically loaded by Claude Code based on:
22
+ - **alwaysApply: true** - Rule is always loaded
23
+ - **alwaysApply: false** - Rule is loaded based on `globs` or `description` relevance
24
+ - **globs** - File patterns that trigger rule loading
25
+
26
+ ## Adding New Rules
27
+
28
+ 1. Choose the appropriate category subdirectory
29
+ 2. Create a `.md` file with frontmatter:
30
+
31
+ ```yaml
32
+ ---
33
+ alwaysApply: false
34
+ description: "Brief description for relevance matching"
35
+ globs: src/**/*.ts # Optional: only load for these files
36
+ ---
37
+ ```
38
+
39
+ 3. Write the rule content in markdown
40
+
41
+ ## Categories
42
+
43
+ | Category | Purpose |
44
+ |----------|---------|
45
+ | code-style | Naming conventions, formatting, file structure |
46
+ | security | Security patterns, input validation, safe practices |
47
+ | architecture | Design decisions, component patterns, system organization |
48
+
49
+ ## Auto-Generation
50
+
51
+ Some rules can be auto-generated from `.workflow/state/decisions.md`:
52
+
53
+ ```bash
54
+ node scripts/flow-rules-sync.js
55
+ ```
56
+
57
+ The sync script will route rules to appropriate category subdirectories.
58
+
59
+ ---
60
+ Last updated: 2026-01-12
@@ -0,0 +1,38 @@
1
+ ---
2
+ globs: src/components/**/*
3
+ alwaysApply: false
4
+ description: "Component reuse policy - always check app-map.md before creating components"
5
+ ---
6
+
7
+ # Component Reuse Policy
8
+
9
+ **Rule**: Always check `app-map.md` before creating any component.
10
+
11
+ ## Priority Order
12
+
13
+ 1. **Use existing** - Check if component already exists in app-map
14
+ 2. **Add variant** - Extend existing component with a new variant
15
+ 3. **Extend** - Create a wrapper/HOC around existing component
16
+ 4. **Create new** - Only as last resort
17
+
18
+ ## Before Creating Components
19
+
20
+ ```bash
21
+ # Check app-map first
22
+ cat .workflow/state/app-map.md | grep -i "button"
23
+
24
+ # Or search codebase
25
+ grep -r "Button" src/components/
26
+ ```
27
+
28
+ ## Variant vs New Component
29
+
30
+ Prefer variants when:
31
+ - Same base functionality, different appearance
32
+ - Same HTML structure, different styling
33
+ - Same component, different size/color/state
34
+
35
+ Create new component when:
36
+ - Fundamentally different functionality
37
+ - Different DOM structure
38
+ - Different state management
@@ -0,0 +1,76 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "All AI-context documents must use PIN markers for targeted context loading"
4
+ ---
5
+
6
+ # Document Structure for AI Context
7
+
8
+ All documents in `.workflow/` that are used as AI context MUST follow the PIN standard.
9
+
10
+ ## Required Structure
11
+
12
+ ### 1. Header with PIN List
13
+ Every document starts with a comment listing all pins in the document:
14
+ ```markdown
15
+ <!-- PINS: pin1, pin2, pin3 -->
16
+ ```
17
+
18
+ ### 2. Section PIN Markers
19
+ Each major section has a PIN marker comment:
20
+ ```markdown
21
+ ### Section Title
22
+ <!-- PIN: section-specific-pin -->
23
+ [Content]
24
+ ```
25
+
26
+ ### 3. PIN Naming Convention
27
+ - Use kebab-case: `user-authentication`, not `userAuthentication`
28
+ - Use semantic names: `error-handling`, not `eh`
29
+ - Use compound names for specificity: `json-parse-safety`
30
+
31
+ ## Why PINs Matter
32
+
33
+ The PIN system enables:
34
+ 1. **Targeted context loading**: Only load sections relevant to current task
35
+ 2. **Cheaper model routing**: Haiku can fetch only relevant sections for Opus
36
+ 3. **Change detection**: Hash sections independently for smart invalidation
37
+ 4. **Cross-reference**: Link sections by PIN across documents
38
+
39
+ ## Example Document
40
+
41
+ ```markdown
42
+ # Config Reference
43
+
44
+ <!-- PINS: database, authentication, api-keys, environment -->
45
+
46
+ ## Database Settings
47
+ <!-- PIN: database -->
48
+ | Setting | Default | Description |
49
+ |---------|---------|-------------|
50
+
51
+ ## Authentication
52
+ <!-- PIN: authentication -->
53
+ | Setting | Default | Description |
54
+ |---------|---------|-------------|
55
+ ```
56
+
57
+ ## Parsing
58
+
59
+ The PIN system automatically parses documents with:
60
+ - `flow-section-index.js` - Generates section index with pins
61
+ - `flow-section-resolver.js` - Resolves sections by PIN lookup
62
+ - `getSectionsByPins(['auth', 'security'])` - Fetch only relevant sections
63
+
64
+ ## Files That Must Have PINs
65
+
66
+ | File | Required PINs |
67
+ |------|---------------|
68
+ | `decisions.md` | Per coding rule/pattern |
69
+ | `app-map.md` | Per component/screen |
70
+ | `product.md` | Per product section |
71
+ | `stack.md` | Per technology |
72
+
73
+ ## Validation
74
+
75
+ Run `node scripts/flow-section-index.js --force` to regenerate the index.
76
+ Check `.workflow/state/section-index.json` for indexed sections and their pins.
@@ -0,0 +1,87 @@
1
+ ---
2
+ alwaysApply: false
3
+ description: "Cleanup checklist when refactoring or renaming features"
4
+ globs:
5
+ - "scripts/*.js"
6
+ - ".claude/skills/**/*"
7
+ ---
8
+
9
+ # Feature Refactoring Cleanup
10
+
11
+ When refactoring, renaming, or replacing a feature, ensure complete cleanup of the old implementation.
12
+
13
+ ## Mandatory Cleanup Checklist
14
+
15
+ When a feature is refactored or renamed, you MUST:
16
+
17
+ ### 1. Remove Old Code
18
+ - [ ] Delete old script files (e.g., `flow-old-feature.js`)
19
+ - [ ] Remove old skill directories (e.g., `.claude/skills/old-feature/`)
20
+ - [ ] Remove old hook files if applicable
21
+
22
+ ### 2. Update Configuration
23
+ - [ ] Rename config keys (e.g., `oldFeature` → `newFeature`)
24
+ - [ ] Remove from `skills.installed` array if skill was removed
25
+ - [ ] Update any feature flags
26
+
27
+ ### 3. Update Documentation
28
+ - [ ] Rename/update doc files in `.claude/docs/`
29
+ - [ ] Update command references in `commands.md`
30
+ - [ ] Update skill-matching.md if skill changed
31
+ - [ ] Search for old name in all `.md` files
32
+
33
+ ### 4. Clean References
34
+ - [ ] Search codebase: `grep -r "old-feature-name" .`
35
+ - [ ] Update imports in dependent scripts
36
+ - [ ] Update any hardcoded references
37
+
38
+ ### 5. Update State Files
39
+ - [ ] Clean `.workflow/state/` of old state files
40
+ - [ ] Update `ready.json` if tasks reference old feature
41
+ - [ ] Archive old change specs
42
+
43
+ ## Search Commands
44
+
45
+ Run these to find lingering references:
46
+
47
+ ```bash
48
+ # Find all references to old feature
49
+ grep -r "old-feature-name" --include="*.js" --include="*.md" --include="*.json" .
50
+
51
+ # Find in config
52
+ grep "oldFeatureName" .workflow/config.json
53
+
54
+ # Find skill references
55
+ grep -r "old-feature" .claude/
56
+ ```
57
+
58
+ ## Why This Matters
59
+
60
+ Incomplete cleanup causes:
61
+ - **Confusion**: Old commands/skills appear to work but don't
62
+ - **Bloat**: Dead code accumulates
63
+ - **Errors**: Old references cause runtime failures
64
+ - **Documentation drift**: Docs describe non-existent features
65
+
66
+ ## Example: transcript-digestion → long-input-gate
67
+
68
+ When this refactoring happened without proper cleanup:
69
+
70
+ | Artifact | Status | Should Have Been |
71
+ |----------|--------|------------------|
72
+ | `.claude/skills/transcript-digestion/` | Left behind | Deleted |
73
+ | `config.transcriptDigestion` | Left as-is | Renamed to `longInputGate` |
74
+ | `skills.installed` array | Still listed | Removed |
75
+ | `skill-matching.md` | Old references | Updated |
76
+ | `transcript-digestion.md` doc | Still existed | Renamed/rewritten |
77
+
78
+ ## Automation Opportunity
79
+
80
+ Consider adding a `flow refactor-cleanup <old-name> <new-name>` command that:
81
+ 1. Searches for all references
82
+ 2. Shows what needs updating
83
+ 3. Optionally auto-updates simple cases
84
+
85
+ ---
86
+
87
+ Last updated: 2026-01-14
@@ -0,0 +1,35 @@
1
+ ---
2
+ globs: scripts/flow-model*.js
3
+ alwaysApply: false
4
+ description: "Model management architecture - two separate systems for different purposes"
5
+ ---
6
+
7
+ # Model Management Architecture
8
+
9
+ **Context**: Phase 1 introduced model registry and stats system alongside existing model-adapter.
10
+
11
+ ## Two Model Systems
12
+
13
+ ### 1. flow-model-adapter.js - Prompt Adaptation
14
+
15
+ - `getCurrentModel()` returns normalized model name (string)
16
+ - Focus: Per-model prompt adjustments, learning, and corrections
17
+ - Imports: Used by flow-knowledge-router.js
18
+
19
+ ### 2. flow-models.js - Registry and Stats
20
+
21
+ - `getCurrentModel()` returns `{name, info, source}` object
22
+ - Focus: Model listing, routing recommendations, cost tracking
23
+ - Standalone CLI commands: `flow models [subcommand]`
24
+
25
+ ## Design Decision
26
+
27
+ **Keep them separate** because:
28
+ - Different return types serve different consumers
29
+ - Adapter system needs just the name for pattern matching
30
+ - Registry system needs full model metadata for display/routing
31
+ - Merging would create unnecessary coupling
32
+
33
+ ## Future Consideration
34
+
35
+ Could extract shared model detection logic into a common utility if they drift apart, but avoid premature abstraction.
@@ -0,0 +1,87 @@
1
+ ---
2
+ description: "Patterns for modifying WogiFlow itself (scripts, templates, config)"
3
+ alwaysApply: false
4
+ globs: "scripts/**,*.workflow/**,.claude/**,templates/**,agents/**,lib/**"
5
+ ---
6
+
7
+ # WogiFlow Self-Maintenance Patterns
8
+
9
+ When modifying WogiFlow's own code (scripts/, templates/, config, hooks), follow these patterns.
10
+
11
+ ## 1. Template-First Changes
12
+
13
+ CLAUDE.md is **generated**, not hand-edited. Changes must go through the template system:
14
+
15
+ ```
16
+ .workflow/templates/claude-md.hbs # Main template
17
+ .workflow/templates/partials/*.hbs # Partial templates
18
+ ```
19
+
20
+ After editing templates, regenerate:
21
+ ```bash
22
+ node scripts/flow-bridge.js sync claude-code
23
+ ```
24
+
25
+ **Never edit CLAUDE.md directly** - changes will be overwritten on next sync.
26
+
27
+ ## 2. Three-Layer Hook Architecture
28
+
29
+ All hooks follow: Entry → Core → Adapter
30
+
31
+ ```
32
+ scripts/hooks/entry/claude-code/<name>.js # CLI-specific entry point
33
+ scripts/hooks/core/<name>.js # CLI-agnostic logic
34
+ scripts/hooks/adapters/claude-code.js # Transform results
35
+ ```
36
+
37
+ When adding/modifying hooks:
38
+ - Logic goes in `core/` (not entry)
39
+ - Entry files only parse input and call core
40
+ - Register hook in `.claude/settings.local.json`
41
+ - Add config toggle in `.workflow/config.json` under `hooks.rules`
42
+
43
+ ## 3. Config Changes Need Documentation
44
+
45
+ When adding config keys:
46
+ - Use `_comment_<keyName>` for inline documentation of non-obvious settings
47
+ - Update config.schema.json if it exists
48
+ - Ensure `lib/installer.js` handles the new key for fresh installs
49
+
50
+ ## 4. State File Templates
51
+
52
+ For files in `.workflow/state/` that target projects need:
53
+ - Create both the file AND a `.template` version
54
+ - Templates go in `.workflow/state/<name>.template` (for init/onboard)
55
+ - Also add to `templates/` directory (for npm distribution)
56
+
57
+ ## 5. Slash Commands Are Flat Files
58
+
59
+ Slash commands in `.claude/commands/` must be flat `.md` files:
60
+ ```
61
+ .claude/commands/wogi-start.md ← Correct (flat file)
62
+ .claude/commands/wogi-start/ ← Wrong (directory)
63
+ ```
64
+
65
+ ## 6. Two Agent Directories
66
+
67
+ | Directory | Purpose | Used By |
68
+ |-----------|---------|---------|
69
+ | `agents/` | 11 persona files | Health checks, CLI |
70
+ | `.workflow/agents/` | Review checklists | wogi-review |
71
+
72
+ Don't confuse them. `agents/security.md` (persona) is different from `.workflow/agents/security.md` (OWASP checklist).
73
+
74
+ ## 7. Regression Prevention
75
+
76
+ When modifying flow-*.js scripts:
77
+ - Run `node --check scripts/<file>.js` after edits
78
+ - WogiFlow has no test suite - syntax checking is the safety net
79
+ - Check for circular dependencies when moving shared functions
80
+
81
+ ## 8. Feature Refactoring Cleanup
82
+
83
+ When renaming/replacing a feature, follow the full checklist in `.claude/rules/architecture/feature-refactoring-cleanup.md`. Key steps:
84
+ - Remove old script files
85
+ - Update config keys
86
+ - Update documentation references
87
+ - Search all `.md` files for old name
@@ -0,0 +1,55 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "Naming conventions for files and code variants"
4
+ ---
5
+
6
+ # Naming Conventions
7
+
8
+ ## File Names
9
+
10
+ Use **kebab-case** for all file names in this project.
11
+
12
+ Examples:
13
+ - `flow-health.js` (correct)
14
+ - `flowHealth.js` (incorrect)
15
+ - `flow_health.js` (incorrect)
16
+
17
+ ## Variant Names
18
+
19
+ Use consistent variant names for components:
20
+
21
+ | Category | Values |
22
+ |----------|--------|
23
+ | Size | `sm`, `md`, `lg`, `xl` |
24
+ | Intent | `primary`, `secondary`, `danger`, `success`, `warning` |
25
+ | State | `default`, `hover`, `active`, `disabled` |
26
+
27
+ Examples:
28
+ ```jsx
29
+ <Button size="sm" intent="primary" />
30
+ <Badge variant="warning" />
31
+ ```
32
+
33
+ ## Catch Block Variables
34
+
35
+ Use `err` for all catch blocks in this codebase.
36
+
37
+ **Avoid**: `e`, `error`, `ex`, `exception` - these cause confusion with loop variables.
38
+
39
+ ```javascript
40
+ // Good
41
+ try {
42
+ doSomething();
43
+ } catch (err) {
44
+ console.error(err.message);
45
+ }
46
+
47
+ // Bad - 'e' conflicts with common iterator variables
48
+ try {
49
+ items.map(e => e.value); // 'e' used as iterator
50
+ } catch (e) {
51
+ console.error(e.message); // Easy to confuse with iterator 'e'
52
+ }
53
+ ```
54
+
55
+ **Reason**: Standardizing on `err` prevents mix-ups when `.map(e => ...)` is used nearby.
@@ -0,0 +1,176 @@
1
+ ---
2
+ alwaysApply: true
3
+ description: "Security patterns for file operations, JSON parsing, and path handling"
4
+ ---
5
+
6
+ # Security Patterns
7
+
8
+ Critical security patterns for this project.
9
+
10
+ ## 1. File Read Safety
11
+
12
+ Always wrap `fs.readFileSync()` in try-catch, even after `fileExists()` check.
13
+
14
+ **Reason**: Race conditions, permission changes, symlink issues can still cause failures.
15
+
16
+ ```javascript
17
+ // Good
18
+ try {
19
+ const content = fs.readFileSync(path, 'utf-8');
20
+ } catch (err) {
21
+ // Handle gracefully
22
+ }
23
+
24
+ // Bad - can still throw even if file existed
25
+ if (fs.existsSync(path)) {
26
+ const content = fs.readFileSync(path, 'utf-8');
27
+ }
28
+ ```
29
+
30
+ ## 2. JSON Parsing Safety
31
+
32
+ Use `safeJsonParse()` from flow-utils.js instead of raw `JSON.parse()`.
33
+
34
+ - Check for `__proto__`, `constructor`, `prototype` injection
35
+ - Validate parsed structure has expected fields before use
36
+ - Located in: `scripts/flow-utils.js`
37
+
38
+ ```javascript
39
+ // Good
40
+ const config = safeJsonParse(filePath, {});
41
+
42
+ // Bad - vulnerable to prototype pollution
43
+ const config = JSON.parse(fs.readFileSync(filePath));
44
+ ```
45
+
46
+ ## 3. Template Substitution Safety
47
+
48
+ When implementing template substitution:
49
+ - Block access to `__proto__`, `constructor`, `prototype` keys
50
+ - Use `Object.prototype.hasOwnProperty.call()` for property access
51
+ - Example: See `applyTemplate()` in flow-prompt-composer.js
52
+
53
+ ## 4. Path Safety
54
+
55
+ - Validate patterns before `path.join()` with user/config data
56
+ - Use `isPathWithinProject()` for defense-in-depth
57
+ - Glob-to-regex: Use `[^/]*` not `.*` to prevent path separator matching
58
+
59
+ ```javascript
60
+ // Good
61
+ if (!isPathWithinProject(targetPath)) {
62
+ throw new Error('Path outside project');
63
+ }
64
+
65
+ // Bad - allows path traversal
66
+ const fullPath = path.join(baseDir, userInput);
67
+ ```
68
+
69
+ ## 5. Module Dependencies
70
+
71
+ - Check for circular dependencies when refactoring shared functions
72
+ - Node.js handles circular deps but can cause undefined exports during load
73
+
74
+ ## 6. Claude Code Permission Patterns (2.1.7+)
75
+
76
+ When configuring permission rules in Claude Code, avoid overly permissive wildcards.
77
+
78
+ **Vulnerability fixed in 2.1.7**: Wildcard permission rules could match compound commands containing shell operators (`;`, `&&`, `||`, `|`).
79
+
80
+ ```javascript
81
+ // DANGEROUS - could match "npm test && rm -rf /"
82
+ "allow": "npm *"
83
+
84
+ // SAFER - be specific about allowed commands
85
+ "allow": "npm test"
86
+ "allow": "npm run build"
87
+ "allow": "npm install"
88
+
89
+ // BEST - use semantic prompts instead of wildcards
90
+ // In ExitPlanMode allowedPrompts:
91
+ { "tool": "Bash", "prompt": "run tests" }
92
+ { "tool": "Bash", "prompt": "install dependencies" }
93
+ ```
94
+
95
+ **Best practices:**
96
+ - Avoid `*` wildcards in permission rules
97
+ - Use specific command patterns
98
+ - Prefer semantic permission prompts over literal command matching
99
+ - Never allow broad patterns like `rm *` or `git *`
100
+ - Review permission rules after Claude Code updates
101
+
102
+ ## 7. Windows Path Safety
103
+
104
+ On Windows, be aware of path-related issues:
105
+
106
+ - Temp directory paths may contain characters like `\t` or `\n` that could be misinterpreted as escape sequences
107
+ - Use raw strings or proper escaping when constructing paths
108
+ - Cloud sync tools (OneDrive, Dropbox) and antivirus may touch file timestamps without changing content
109
+
110
+ ```javascript
111
+ // Good - use path.join() which handles platform differences
112
+ const tempPath = path.join(os.tmpdir(), 'myfile.txt');
113
+
114
+ // Bad - manual concatenation can break on Windows
115
+ const tempPath = os.tmpdir() + '/myfile.txt';
116
+ ```
117
+
118
+ ## 8. Shell Command Parameter Validation
119
+
120
+ When executing shell commands with dynamic parameters, always validate inputs.
121
+
122
+ **Risk**: Command injection via unvalidated parameters passed to execSync/spawn.
123
+
124
+ ```javascript
125
+ // DANGEROUS - lang parameter not validated
126
+ execSync(`sg --pattern "${pattern}" --lang ${lang} --json "${path}"`);
127
+
128
+ // SAFER - validate against whitelist
129
+ const ALLOWED_LANGUAGES = new Set(['typescript', 'javascript', 'python', 'go']);
130
+ if (!ALLOWED_LANGUAGES.has(lang)) {
131
+ throw new Error(`Unsupported language: ${lang}`);
132
+ }
133
+
134
+ // BEST - use execFile with array arguments (no shell interpretation)
135
+ const { execFileSync } = require('child_process');
136
+ execFileSync('sg', ['--pattern', pattern, '--lang', lang, '--json', path]);
137
+ ```
138
+
139
+ **Best practices:**
140
+ - Validate all dynamic parameters against allowlists
141
+ - Prefer `execFile`/`execFileSync` with array arguments over `exec`/`execSync` with template strings
142
+ - When using template strings, escape all user-controlled values
143
+ - Never interpolate user input directly into shell commands
144
+
145
+ ## 9. Temp Directory Isolation (Claude Code 2.1.23+)
146
+
147
+ On shared systems (CI servers, multi-user machines), use per-user temp directories to prevent permission conflicts.
148
+
149
+ **Fixed in Claude Code 2.1.23**: Per-user temp directory isolation prevents permission conflicts.
150
+
151
+ ```javascript
152
+ // Good - per-user isolation
153
+ const userId = process.getuid?.() ?? process.env.USER ?? process.env.USERNAME ?? 'default';
154
+ const tempDir = path.join(os.tmpdir(), `myapp-${userId}`);
155
+
156
+ // Bad - global temp path on shared systems
157
+ const tempDir = path.join(os.tmpdir(), 'myapp');
158
+ ```
159
+
160
+ **Best practices:**
161
+ - Use UID on Unix systems (`process.getuid()`)
162
+ - Fall back to username environment variables on Windows
163
+ - Always provide a 'default' fallback for edge cases
164
+ - This pattern is used in `flow-worktree.js` for worktree isolation
165
+
166
+ ## 10. Search/Grep Timeout Handling (Claude Code 2.1.23+)
167
+
168
+ **Fixed in Claude Code 2.1.23**: Ripgrep search timeouts now report errors instead of silently returning empty results.
169
+
170
+ **Impact on WogiFlow:** Component detection, auto-context loading, and pattern matching rely on search operations. Before 2.1.23, search timeouts could cause false negatives.
171
+
172
+ **Best practices:**
173
+ - Handle empty search results gracefully - they may indicate timeout
174
+ - Add retry logic for search-dependent operations
175
+ - Log warnings when searches return unexpectedly empty
176
+ - Consider fallback strategies (glob-based search if grep fails)
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "PreToolUse": [
37
37
  {
38
- "matcher": "Edit|Write|TodoWrite|Skill|Bash",
38
+ "matcher": "Edit|Write|TodoWrite|Skill|Bash|EnterPlanMode",
39
39
  "hooks": [
40
40
  {
41
41
  "type": "command",
@@ -115,6 +115,6 @@
115
115
  ]
116
116
  },
117
117
  "_wogiFlowManaged": true,
118
- "_wogiFlowVersion": "1.4.5",
118
+ "_wogiFlowVersion": "1.5.7",
119
119
  "_comment": "Shared WogiFlow hook configuration. Committed to repo for team use. User-specific overrides go in settings.local.json."
120
120
  }
@@ -0,0 +1,11 @@
1
+ # Figma Analyzer Learnings
2
+
3
+ Learnings captured from using the Figma Analyzer skill.
4
+
5
+ ---
6
+
7
+ ## Patterns Learned
8
+
9
+ <!-- Learnings will be captured automatically during skill usage -->
10
+
11
+ ---
@@ -0,0 +1,112 @@
1
+ # Performance Review Agent
2
+
3
+ Expert agent for identifying performance issues in code changes.
4
+
5
+ ## Role
6
+
7
+ Detect performance anti-patterns, inefficient algorithms, and resource management issues.
8
+
9
+ ## Performance Checklist
10
+
11
+ ### Async & Concurrency
12
+ - [ ] No sequential awaits that could be `Promise.all`
13
+ - [ ] No blocking I/O in async contexts
14
+ - [ ] No unhandled promise rejections
15
+ - [ ] Async iterators used efficiently
16
+
17
+ ### Memory Management
18
+ - [ ] Event listeners cleaned up (removeEventListener, unsubscribe)
19
+ - [ ] Large objects released when no longer needed
20
+ - [ ] No closures capturing unnecessary scope
21
+ - [ ] Streams used for large data instead of loading into memory
22
+
23
+ ### Data Access Patterns
24
+ - [ ] No N+1 query patterns (loop with individual DB/API calls)
25
+ - [ ] Batch operations used where available
26
+ - [ ] Results cached when accessed multiple times
27
+ - [ ] Pagination used for large result sets
28
+
29
+ ### Bundle & Import Efficiency
30
+ - [ ] No large library imports when small utility suffices
31
+ - [ ] Dynamic imports for code-split boundaries
32
+ - [ ] Tree-shakeable imports (named vs default)
33
+ - [ ] No duplicate dependencies
34
+
35
+ ### Computation
36
+ - [ ] No unnecessary re-computation (memoize expensive operations)
37
+ - [ ] Appropriate data structures (Map/Set vs Array for lookups)
38
+ - [ ] Early returns to avoid unnecessary work
39
+ - [ ] No redundant iterations (filter+map that could be reduce)
40
+
41
+ ### React-Specific (skip if project does not use React — check package.json for "react" dependency)
42
+ - [ ] Components memoized where appropriate (React.memo, useMemo, useCallback)
43
+ - [ ] No inline object/array creation in render causing re-renders
44
+ - [ ] Keys are stable and meaningful (not array index for dynamic lists)
45
+ - [ ] useEffect dependencies are correct (no missing deps, no over-triggering)
46
+
47
+ ## Common Patterns to Flag
48
+
49
+ ```javascript
50
+ // BAD: Sequential awaits (N+1 pattern)
51
+ for (const id of ids) {
52
+ const result = await fetchItem(id);
53
+ results.push(result);
54
+ }
55
+
56
+ // GOOD: Parallel execution
57
+ const results = await Promise.all(ids.map(id => fetchItem(id)));
58
+ ```
59
+
60
+ ```javascript
61
+ // BAD: Event listener leak
62
+ useEffect(() => {
63
+ window.addEventListener('resize', handler);
64
+ // Missing cleanup!
65
+ }, []);
66
+
67
+ // GOOD: Cleanup on unmount
68
+ useEffect(() => {
69
+ window.addEventListener('resize', handler);
70
+ return () => window.removeEventListener('resize', handler);
71
+ }, []);
72
+ ```
73
+
74
+ ```javascript
75
+ // BAD: Large library for small task
76
+ import _ from 'lodash';
77
+ const unique = _.uniq(items);
78
+
79
+ // GOOD: Use native or targeted import
80
+ const unique = [...new Set(items)];
81
+ ```
82
+
83
+ ## Severity Ratings
84
+
85
+ | Severity | Description | Example |
86
+ |----------|-------------|---------|
87
+ | Critical | Major performance impact at scale | N+1 queries in API endpoint |
88
+ | High | Noticeable performance impact | Memory leak in long-running component |
89
+ | Medium | Suboptimal but functional | Sequential awaits on 2-3 items |
90
+ | Low | Micro-optimization | filter+map vs reduce |
91
+
92
+ ## Review Format
93
+
94
+ ```
95
+ ## File: [path]
96
+
97
+ ### Line [N]: [severity] Performance
98
+ Description of the performance issue.
99
+
100
+ **Impact**: [What gets slower/uses more resources]
101
+ **Pattern**: [Name of the anti-pattern]
102
+
103
+ **Current:**
104
+ \`\`\`
105
+ [current code]
106
+ \`\`\`
107
+
108
+ **Suggested:**
109
+ \`\`\`
110
+ [optimized code]
111
+ \`\`\`
112
+ ```
@@ -0,0 +1,24 @@
1
+ # Architecture
2
+
3
+ ## Pattern
4
+
5
+ <!-- Detected during onboarding -->
6
+ <!-- Examples: MVC, Clean Architecture, DDD, Microservices, Monolith -->
7
+
8
+ ## Structure
9
+
10
+ <!-- Project structure overview -->
11
+ <!-- Key directories and their purposes -->
12
+
13
+ ## Key Decisions
14
+
15
+ <!-- Architecture decisions made for this project -->
16
+ <!-- Trade-offs and rationale -->
17
+
18
+ ## Dependencies
19
+
20
+ <!-- Major dependencies and their purposes -->
21
+
22
+ ---
23
+
24
+ *This file is auto-populated during `flow onboard`. Update manually as architecture evolves.*
@@ -0,0 +1,33 @@
1
+ # Tech Stack
2
+
3
+ ## Framework
4
+
5
+ <!-- Primary framework (e.g., Next.js, NestJS, FastAPI) -->
6
+
7
+ ## Language
8
+
9
+ <!-- Primary language (e.g., TypeScript, Python, Go) -->
10
+
11
+ ## Database
12
+
13
+ <!-- Database system if applicable (e.g., PostgreSQL, MongoDB) -->
14
+
15
+ ## Package Manager
16
+
17
+ <!-- npm, yarn, pnpm, pip, etc. -->
18
+
19
+ ## Build Tools
20
+
21
+ <!-- Build and bundling tools (e.g., Vite, Webpack, esbuild) -->
22
+
23
+ ## Testing
24
+
25
+ <!-- Test frameworks (e.g., Jest, Vitest, pytest) -->
26
+
27
+ ## Other Tools
28
+
29
+ <!-- Linters, formatters, CI/CD tools -->
30
+
31
+ ---
32
+
33
+ *This file is auto-populated during `flow onboard`. Update manually as stack evolves.*
@@ -0,0 +1,36 @@
1
+ # Testing
2
+
3
+ ## Test Framework
4
+
5
+ <!-- Primary test framework (e.g., Jest, Vitest, pytest) -->
6
+
7
+ ## Test Commands
8
+
9
+ ```bash
10
+ # Run all tests
11
+ npm test
12
+
13
+ # Run tests in watch mode
14
+ npm run test:watch
15
+
16
+ # Run specific test file
17
+ npm test -- path/to/test.ts
18
+ ```
19
+
20
+ ## Test Structure
21
+
22
+ <!-- Where tests are located -->
23
+ <!-- Naming conventions -->
24
+
25
+ ## Coverage
26
+
27
+ <!-- Coverage requirements if any -->
28
+ <!-- Coverage commands -->
29
+
30
+ ## E2E Testing
31
+
32
+ <!-- E2E framework if used (e.g., Playwright, Cypress) -->
33
+
34
+ ---
35
+
36
+ *This file is auto-populated during `flow onboard`. Update manually as testing strategy evolves.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wogiflow",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "description": "AI-powered development workflow management system with multi-model support",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -18,7 +18,10 @@ const path = require('path');
18
18
 
19
19
  const { getConfig, getReadyData, PATHS } = require('../../flow-utils');
20
20
 
21
- const ROUTING_FLAG_PATH = path.join(PATHS.state, '.routing-pending');
21
+ // Include session ID in flag path to prevent concurrent sessions from
22
+ // interfering with each other. Falls back to PID-based path if no session ID.
23
+ const SESSION_ID = process.env.CLAUDE_CODE_SESSION_ID || `pid-${process.ppid || process.pid}`;
24
+ const ROUTING_FLAG_PATH = path.join(PATHS.state, `.routing-pending-${SESSION_ID}`);
22
25
 
23
26
  /**
24
27
  * Check if routing gate is enabled in config
@@ -32,8 +35,10 @@ function isRoutingGateEnabled() {
32
35
  if (process.env.DEBUG) {
33
36
  console.error(`[routing-gate] Config read error: ${err.message}`);
34
37
  }
35
- // Fail-open: if config can't be read, don't enforce
36
- return false;
38
+ // Fail-closed: if config can't be read, enforce the gate.
39
+ // Users who installed WogiFlow expect routing enforcement.
40
+ // Failing open here would silently bypass routing on config corruption.
41
+ return true;
37
42
  }
38
43
  }
39
44
 
@@ -118,8 +123,10 @@ function clearRoutingPending() {
118
123
  }
119
124
  }
120
125
 
121
- // Max age for routing flag before it's considered stale (5 minutes)
122
- const ROUTING_FLAG_TTL_MS = 5 * 60 * 1000;
126
+ // Max age for routing flag before it's considered stale (30 minutes)
127
+ // 5 min was too short complex tasks with explore phases, spec generation,
128
+ // and approval gates can take 15-20 min before first Bash call.
129
+ const ROUTING_FLAG_TTL_MS = 30 * 60 * 1000;
123
130
 
124
131
  /**
125
132
  * Check if the routing-pending flag is set and not stale
@@ -123,7 +123,9 @@ async function main() {
123
123
  // When users type "/wogi-start ..." directly, Claude Code expands the skill inline
124
124
  // (not through the Skill tool), so clearRoutingPending() in PreToolUse never fires.
125
125
  // Setting the flag here would create an uncleable block.
126
- const isWogiCommand = typeof prompt === 'string' && /^\/(wogi-\S+)/i.test(prompt.trim());
126
+ // Tightened regex: only match /wogi-[lowercase-alphanumeric-hyphens] to prevent
127
+ // injection via crafted prompts like "/wogi-<script>" or "/wogi-../../path"
128
+ const isWogiCommand = typeof prompt === 'string' && /^\/wogi-[a-z0-9-]+\b/i.test(prompt.trim());
127
129
  if (!isWogiCommand) {
128
130
  try {
129
131
  setRoutingPending();
@@ -30,13 +30,42 @@ const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
30
30
  const DIR_MODE = 0o755; // rwxr-xr-x for directories
31
31
  const FILE_MODE = 0o644; // rw-r--r-- for files
32
32
 
33
+ // Dangerous keys for prototype pollution protection
34
+ const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
35
+
36
+ /**
37
+ * Safe JSON parse with prototype pollution protection.
38
+ * Inline copy — postinstall.js can't reliably require flow-utils.js
39
+ * because it runs from npm context before scripts/ is fully copied.
40
+ * @param {string} jsonString - JSON string to parse
41
+ * @param {*} defaultValue - Default value on parse failure
42
+ * @returns {Object} Parsed object or defaultValue
43
+ */
44
+ function safeJsonParseString(jsonString, defaultValue = null) {
45
+ try {
46
+ const parsed = JSON.parse(jsonString);
47
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
48
+ return defaultValue;
49
+ }
50
+ // Check top-level keys for prototype pollution
51
+ for (const key of Object.keys(parsed)) {
52
+ if (DANGEROUS_KEYS.has(key)) {
53
+ return defaultValue;
54
+ }
55
+ }
56
+ return parsed;
57
+ } catch (err) {
58
+ return defaultValue;
59
+ }
60
+ }
61
+
33
62
  /**
34
63
  * Safely close a file descriptor, ignoring errors
35
64
  * @param {number|null} fd - File descriptor to close
36
65
  */
37
66
  function safeClose(fd) {
38
67
  if (fd !== null) {
39
- try { fs.closeSync(fd); } catch (_err) { /* intentionally ignored */ }
68
+ try { fs.closeSync(fd); } catch (err) { /* intentionally ignored */ }
40
69
  }
41
70
  }
42
71
 
@@ -195,11 +224,9 @@ function copyClaudeResources() {
195
224
  if (fs.existsSync(projectSettings)) {
196
225
  // Always merge hooks from package into existing settings
197
226
  try {
198
- const existingRaw = JSON.parse(fs.readFileSync(projectSettings, 'utf-8'));
199
- const oursRaw = JSON.parse(fs.readFileSync(packageSettings, 'utf-8'));
200
- // Guard against prototype pollution from untrusted JSON
201
- const existing = (existingRaw && typeof existingRaw === 'object' && !Array.isArray(existingRaw)) ? existingRaw : {};
202
- const ours = (oursRaw && typeof oursRaw === 'object' && !Array.isArray(oursRaw)) ? oursRaw : {};
227
+ // Use safeJsonParseString for prototype pollution protection
228
+ const existing = safeJsonParseString(fs.readFileSync(projectSettings, 'utf-8'), {});
229
+ const ours = safeJsonParseString(fs.readFileSync(packageSettings, 'utf-8'), {});
203
230
  // Always update hooks (core WogiFlow functionality)
204
231
  existing.hooks = ours.hooks;
205
232
  existing._wogiFlowManaged = true;
@@ -224,7 +251,7 @@ function copyClaudeResources() {
224
251
  fs.copyFileSync(packageSettings, projectSettings);
225
252
  try {
226
253
  fs.chmodSync(projectSettings, FILE_MODE);
227
- } catch (_err) { /* non-critical */ }
254
+ } catch (err) { /* non-critical */ }
228
255
  } catch (err) {
229
256
  if (process.env.DEBUG) {
230
257
  console.error(`[postinstall] settings.json initial copy failed: ${err.message}`);
@@ -288,6 +315,45 @@ function copyWorkflowManagedDirs() {
288
315
  }
289
316
  }
290
317
 
318
+ /**
319
+ * Regenerate CLAUDE.md from templates (for npm update scenario)
320
+ * Only runs when config.json exists (project already initialized).
321
+ * Uses the bridge's synchronous generateRulesFile() to avoid async in postinstall.
322
+ */
323
+ function regenerateClaudeMd() {
324
+ // Only regenerate if project is already initialized (has config.json)
325
+ if (!fs.existsSync(path.join(WORKFLOW_DIR, 'config.json'))) {
326
+ return;
327
+ }
328
+
329
+ try {
330
+ // Load the bridge module from the project's .workflow/bridges/
331
+ const bridgesPath = path.join(PROJECT_ROOT, '.workflow', 'bridges');
332
+ if (!fs.existsSync(path.join(bridgesPath, 'index.js'))) {
333
+ if (process.env.DEBUG) {
334
+ console.error('[postinstall] Bridge module not found, skipping CLAUDE.md regen');
335
+ }
336
+ return;
337
+ }
338
+
339
+ const { getBridge } = require(bridgesPath);
340
+ const bridge = getBridge({ projectDir: PROJECT_ROOT });
341
+
342
+ // generateRulesFile() is synchronous — safe to call from postinstall
343
+ // force: true ensures templates always win over stale CLAUDE.md
344
+ bridge.generateRulesFile({ force: true });
345
+
346
+ if (process.env.DEBUG) {
347
+ console.error('[postinstall] Regenerated CLAUDE.md from templates');
348
+ }
349
+ } catch (err) {
350
+ // Non-fatal — CLAUDE.md regeneration failure shouldn't break npm install
351
+ if (process.env.DEBUG) {
352
+ console.error(`[postinstall] CLAUDE.md regen failed: ${err.message}`);
353
+ }
354
+ }
355
+ }
356
+
291
357
  /**
292
358
  * Check if we should be completely silent (CI only)
293
359
  */
@@ -324,6 +390,11 @@ function main() {
324
390
  // Always overwrite — these are package-managed, not user-customizable.
325
391
  copyWorkflowManagedDirs();
326
392
 
393
+ // Regenerate CLAUDE.md from updated templates (for npm update scenario)
394
+ // This ensures the AI reads fresh instructions matching the new package version.
395
+ // Must run AFTER copyWorkflowManagedDirs() so templates/bridges are up to date.
396
+ regenerateClaudeMd();
397
+
327
398
  // Create marker for AI to detect (unless already initialized)
328
399
  createPendingSetupMarker();
329
400
 
@@ -343,7 +414,7 @@ function main() {
343
414
  // Combine access check and open into single try-catch to avoid TOCTOU
344
415
  ttyFd = fs.openSync('/dev/tty', 'w');
345
416
  output = { write: (msg) => fs.writeSync(ttyFd, msg) };
346
- } catch (_err) {
417
+ } catch (err) {
347
418
  // /dev/tty not available (no terminal, CI, etc.) - fallback to stderr
348
419
  ttyFd = null;
349
420
  }