wogiflow 1.0.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.
Files changed (221) hide show
  1. package/.workflow/agents/reviewer.md +81 -0
  2. package/.workflow/agents/security.md +94 -0
  3. package/.workflow/agents/story-writer.md +58 -0
  4. package/.workflow/bridges/base-bridge.js +395 -0
  5. package/.workflow/bridges/claude-bridge.js +434 -0
  6. package/.workflow/bridges/index.js +130 -0
  7. package/.workflow/lib/assumption-detector.js +481 -0
  8. package/.workflow/lib/config-substitution.js +371 -0
  9. package/.workflow/lib/failure-categories.js +478 -0
  10. package/.workflow/state/app-map.md.template +15 -0
  11. package/.workflow/state/architecture.md.template +24 -0
  12. package/.workflow/state/component-index.json.template +5 -0
  13. package/.workflow/state/decisions.md.template +15 -0
  14. package/.workflow/state/feedback-patterns.md.template +9 -0
  15. package/.workflow/state/knowledge-sync.json.template +6 -0
  16. package/.workflow/state/progress.md.template +14 -0
  17. package/.workflow/state/ready.json.template +7 -0
  18. package/.workflow/state/request-log.md.template +14 -0
  19. package/.workflow/state/session-state.json.template +11 -0
  20. package/.workflow/state/stack.md.template +33 -0
  21. package/.workflow/state/testing.md.template +36 -0
  22. package/.workflow/templates/claude-md.hbs +257 -0
  23. package/.workflow/templates/correction-report.md +67 -0
  24. package/.workflow/templates/gemini-md.hbs +52 -0
  25. package/README.md +1802 -0
  26. package/bin/flow +205 -0
  27. package/lib/index.js +33 -0
  28. package/lib/installer.js +467 -0
  29. package/lib/release-channel.js +269 -0
  30. package/lib/skill-registry.js +526 -0
  31. package/lib/upgrader.js +401 -0
  32. package/lib/utils.js +305 -0
  33. package/package.json +64 -0
  34. package/scripts/flow +985 -0
  35. package/scripts/flow-adaptive-learning.js +1259 -0
  36. package/scripts/flow-aggregate.js +488 -0
  37. package/scripts/flow-archive +133 -0
  38. package/scripts/flow-auto-context.js +1015 -0
  39. package/scripts/flow-auto-learn.js +615 -0
  40. package/scripts/flow-bridge.js +223 -0
  41. package/scripts/flow-browser-suggest.js +316 -0
  42. package/scripts/flow-bug.js +247 -0
  43. package/scripts/flow-cascade.js +711 -0
  44. package/scripts/flow-changelog +85 -0
  45. package/scripts/flow-checkpoint.js +483 -0
  46. package/scripts/flow-cli.js +403 -0
  47. package/scripts/flow-code-intelligence.js +760 -0
  48. package/scripts/flow-complexity.js +502 -0
  49. package/scripts/flow-config-set.js +152 -0
  50. package/scripts/flow-constants.js +157 -0
  51. package/scripts/flow-context +152 -0
  52. package/scripts/flow-context-init.js +482 -0
  53. package/scripts/flow-context-monitor.js +384 -0
  54. package/scripts/flow-context-scoring.js +886 -0
  55. package/scripts/flow-correct.js +458 -0
  56. package/scripts/flow-damage-control.js +985 -0
  57. package/scripts/flow-deps +101 -0
  58. package/scripts/flow-diff.js +700 -0
  59. package/scripts/flow-done +151 -0
  60. package/scripts/flow-done.js +489 -0
  61. package/scripts/flow-durable-session.js +1541 -0
  62. package/scripts/flow-entropy-monitor.js +345 -0
  63. package/scripts/flow-export-profile +349 -0
  64. package/scripts/flow-export-scanner.js +1046 -0
  65. package/scripts/flow-figma-confirm.js +400 -0
  66. package/scripts/flow-figma-extract.js +496 -0
  67. package/scripts/flow-figma-generate.js +683 -0
  68. package/scripts/flow-figma-index.js +909 -0
  69. package/scripts/flow-figma-match.js +617 -0
  70. package/scripts/flow-figma-mcp-server.js +518 -0
  71. package/scripts/flow-figma-pipeline.js +414 -0
  72. package/scripts/flow-file-ops.js +301 -0
  73. package/scripts/flow-gate-confidence.js +825 -0
  74. package/scripts/flow-guided-edit.js +659 -0
  75. package/scripts/flow-health +185 -0
  76. package/scripts/flow-health.js +413 -0
  77. package/scripts/flow-hooks.js +556 -0
  78. package/scripts/flow-http-client.js +249 -0
  79. package/scripts/flow-hybrid-detect.js +167 -0
  80. package/scripts/flow-hybrid-interactive.js +591 -0
  81. package/scripts/flow-hybrid-test.js +152 -0
  82. package/scripts/flow-import-profile +439 -0
  83. package/scripts/flow-init +253 -0
  84. package/scripts/flow-instruction-richness.js +827 -0
  85. package/scripts/flow-jira-integration.js +579 -0
  86. package/scripts/flow-knowledge-router.js +522 -0
  87. package/scripts/flow-knowledge-sync.js +589 -0
  88. package/scripts/flow-linear-integration.js +631 -0
  89. package/scripts/flow-links.js +774 -0
  90. package/scripts/flow-log-manager.js +559 -0
  91. package/scripts/flow-loop-enforcer.js +1246 -0
  92. package/scripts/flow-loop-retry-learning.js +630 -0
  93. package/scripts/flow-lsp.js +923 -0
  94. package/scripts/flow-map-index +348 -0
  95. package/scripts/flow-map-sync +201 -0
  96. package/scripts/flow-memory-blocks.js +668 -0
  97. package/scripts/flow-memory-compactor.js +350 -0
  98. package/scripts/flow-memory-db.js +1110 -0
  99. package/scripts/flow-memory-sync.js +484 -0
  100. package/scripts/flow-metrics.js +353 -0
  101. package/scripts/flow-migrate-ids.js +370 -0
  102. package/scripts/flow-model-adapter.js +802 -0
  103. package/scripts/flow-model-router.js +884 -0
  104. package/scripts/flow-models.js +1231 -0
  105. package/scripts/flow-morning.js +517 -0
  106. package/scripts/flow-multi-approach.js +660 -0
  107. package/scripts/flow-new-feature +86 -0
  108. package/scripts/flow-onboard +1042 -0
  109. package/scripts/flow-orchestrate-llm.js +459 -0
  110. package/scripts/flow-orchestrate.js +3592 -0
  111. package/scripts/flow-output.js +123 -0
  112. package/scripts/flow-parallel-detector.js +399 -0
  113. package/scripts/flow-parallel-dispatch.js +987 -0
  114. package/scripts/flow-parallel.js +428 -0
  115. package/scripts/flow-pattern-enforcer.js +600 -0
  116. package/scripts/flow-prd-manager.js +282 -0
  117. package/scripts/flow-progress.js +323 -0
  118. package/scripts/flow-project-analyzer.js +975 -0
  119. package/scripts/flow-prompt-composer.js +487 -0
  120. package/scripts/flow-providers.js +1381 -0
  121. package/scripts/flow-queue.js +308 -0
  122. package/scripts/flow-ready +82 -0
  123. package/scripts/flow-ready.js +189 -0
  124. package/scripts/flow-regression.js +396 -0
  125. package/scripts/flow-response-parser.js +450 -0
  126. package/scripts/flow-resume.js +284 -0
  127. package/scripts/flow-rules-sync.js +439 -0
  128. package/scripts/flow-run-trace.js +718 -0
  129. package/scripts/flow-safety.js +587 -0
  130. package/scripts/flow-search +104 -0
  131. package/scripts/flow-security.js +481 -0
  132. package/scripts/flow-session-end +106 -0
  133. package/scripts/flow-session-end.js +437 -0
  134. package/scripts/flow-session-state.js +671 -0
  135. package/scripts/flow-setup-hooks +216 -0
  136. package/scripts/flow-setup-hooks.js +377 -0
  137. package/scripts/flow-skill-create.js +329 -0
  138. package/scripts/flow-skill-creator.js +572 -0
  139. package/scripts/flow-skill-generator.js +1046 -0
  140. package/scripts/flow-skill-learn.js +880 -0
  141. package/scripts/flow-skill-matcher.js +578 -0
  142. package/scripts/flow-spec-generator.js +820 -0
  143. package/scripts/flow-stack-wizard.js +895 -0
  144. package/scripts/flow-standup +162 -0
  145. package/scripts/flow-start +74 -0
  146. package/scripts/flow-start.js +235 -0
  147. package/scripts/flow-status +110 -0
  148. package/scripts/flow-status.js +301 -0
  149. package/scripts/flow-step-browser.js +83 -0
  150. package/scripts/flow-step-changelog.js +217 -0
  151. package/scripts/flow-step-comments.js +306 -0
  152. package/scripts/flow-step-complexity.js +234 -0
  153. package/scripts/flow-step-coverage.js +218 -0
  154. package/scripts/flow-step-knowledge.js +193 -0
  155. package/scripts/flow-step-pr-tests.js +364 -0
  156. package/scripts/flow-step-regression.js +89 -0
  157. package/scripts/flow-step-review.js +516 -0
  158. package/scripts/flow-step-security.js +162 -0
  159. package/scripts/flow-step-silent-failures.js +290 -0
  160. package/scripts/flow-step-simplifier.js +346 -0
  161. package/scripts/flow-story +105 -0
  162. package/scripts/flow-story.js +500 -0
  163. package/scripts/flow-suspend.js +252 -0
  164. package/scripts/flow-sync-daemon.js +654 -0
  165. package/scripts/flow-task-analyzer.js +606 -0
  166. package/scripts/flow-team-dashboard.js +748 -0
  167. package/scripts/flow-team-sync.js +752 -0
  168. package/scripts/flow-team.js +977 -0
  169. package/scripts/flow-tech-options.js +528 -0
  170. package/scripts/flow-templates.js +812 -0
  171. package/scripts/flow-tiered-learning.js +728 -0
  172. package/scripts/flow-trace +204 -0
  173. package/scripts/flow-transcript-chunking.js +1106 -0
  174. package/scripts/flow-transcript-digest.js +7918 -0
  175. package/scripts/flow-transcript-language.js +465 -0
  176. package/scripts/flow-transcript-parsing.js +1085 -0
  177. package/scripts/flow-transcript-stories.js +2194 -0
  178. package/scripts/flow-update-map +224 -0
  179. package/scripts/flow-utils.js +2242 -0
  180. package/scripts/flow-verification.js +644 -0
  181. package/scripts/flow-verify.js +1177 -0
  182. package/scripts/flow-voice-input.js +638 -0
  183. package/scripts/flow-watch +168 -0
  184. package/scripts/flow-workflow-steps.js +521 -0
  185. package/scripts/flow-workflow.js +1029 -0
  186. package/scripts/flow-worktree.js +489 -0
  187. package/scripts/hooks/adapters/base-adapter.js +102 -0
  188. package/scripts/hooks/adapters/claude-code.js +359 -0
  189. package/scripts/hooks/adapters/index.js +79 -0
  190. package/scripts/hooks/core/component-check.js +341 -0
  191. package/scripts/hooks/core/index.js +35 -0
  192. package/scripts/hooks/core/loop-check.js +241 -0
  193. package/scripts/hooks/core/session-context.js +294 -0
  194. package/scripts/hooks/core/task-gate.js +177 -0
  195. package/scripts/hooks/core/validation.js +230 -0
  196. package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
  197. package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
  198. package/scripts/hooks/entry/claude-code/session-end.js +87 -0
  199. package/scripts/hooks/entry/claude-code/session-start.js +46 -0
  200. package/scripts/hooks/entry/claude-code/stop.js +43 -0
  201. package/scripts/postinstall.js +139 -0
  202. package/templates/browser-test-flow.json +56 -0
  203. package/templates/bug-report.md +43 -0
  204. package/templates/component-detail.md +42 -0
  205. package/templates/component.stories.tsx +49 -0
  206. package/templates/context/constraints.md +83 -0
  207. package/templates/context/conventions.md +177 -0
  208. package/templates/context/stack.md +60 -0
  209. package/templates/correction-report.md +90 -0
  210. package/templates/feature-proposal.md +35 -0
  211. package/templates/hybrid/_base.md +254 -0
  212. package/templates/hybrid/_patterns.md +45 -0
  213. package/templates/hybrid/create-component.md +127 -0
  214. package/templates/hybrid/create-file.md +56 -0
  215. package/templates/hybrid/create-hook.md +145 -0
  216. package/templates/hybrid/create-service.md +70 -0
  217. package/templates/hybrid/fix-bug.md +33 -0
  218. package/templates/hybrid/modify-file.md +55 -0
  219. package/templates/story.md +68 -0
  220. package/templates/task.json +56 -0
  221. package/templates/trace.md +69 -0
@@ -0,0 +1,168 @@
1
+ #!/bin/bash
2
+
3
+ # Wogi Flow - File Watcher
4
+ # Runs validation automatically when files change
5
+ # Usage: ./scripts/flow-watch (run in separate terminal)
6
+
7
+ set -e
8
+
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
11
+
12
+ # Colors
13
+ GREEN='\033[0;32m'
14
+ YELLOW='\033[1;33m'
15
+ CYAN='\033[0;36m'
16
+ RED='\033[0;31m'
17
+ DIM='\033[2m'
18
+ NC='\033[0m'
19
+
20
+ show_help() {
21
+ echo "Wogi Flow - File Watcher"
22
+ echo ""
23
+ echo "Automatically runs validation when files change."
24
+ echo "Run this in a separate terminal alongside Claude Code."
25
+ echo ""
26
+ echo "Usage: flow watch [options]"
27
+ echo ""
28
+ echo "Options:"
29
+ echo " --dir DIR Directory to watch (default: src)"
30
+ echo " --ext EXT Extensions to watch (default: ts,tsx,js,jsx)"
31
+ echo " --no-lint Skip eslint"
32
+ echo " --no-types Skip typecheck"
33
+ echo " --help Show this help"
34
+ echo ""
35
+ }
36
+
37
+ WATCH_DIR="src"
38
+ EXTENSIONS="ts,tsx,js,jsx"
39
+ RUN_LINT=true
40
+ RUN_TYPES=true
41
+
42
+ # Parse arguments
43
+ while [[ $# -gt 0 ]]; do
44
+ case $1 in
45
+ --dir)
46
+ WATCH_DIR="$2"
47
+ shift 2
48
+ ;;
49
+ --ext)
50
+ EXTENSIONS="$2"
51
+ shift 2
52
+ ;;
53
+ --no-lint)
54
+ RUN_LINT=false
55
+ shift
56
+ ;;
57
+ --no-types)
58
+ RUN_TYPES=false
59
+ shift
60
+ ;;
61
+ --help|-h)
62
+ show_help
63
+ exit 0
64
+ ;;
65
+ *)
66
+ shift
67
+ ;;
68
+ esac
69
+ done
70
+
71
+ # Check for required tools
72
+ check_requirements() {
73
+ if ! command -v npx &> /dev/null; then
74
+ echo -e "${RED}npx not found. Please install Node.js${NC}"
75
+ exit 1
76
+ fi
77
+
78
+ # Check for nodemon or fswatch or inotifywait
79
+ if command -v nodemon &> /dev/null; then
80
+ WATCHER="nodemon"
81
+ elif command -v fswatch &> /dev/null; then
82
+ WATCHER="fswatch"
83
+ elif command -v inotifywait &> /dev/null; then
84
+ WATCHER="inotify"
85
+ else
86
+ echo -e "${YELLOW}No file watcher found. Installing nodemon...${NC}"
87
+ npm install -g nodemon
88
+ WATCHER="nodemon"
89
+ fi
90
+ }
91
+
92
+ run_validation() {
93
+ local file="$1"
94
+ echo ""
95
+ echo -e "${CYAN}━━━ File Changed: $file ━━━${NC}"
96
+ echo ""
97
+
98
+ local has_errors=false
99
+
100
+ # TypeScript check
101
+ if [ "$RUN_TYPES" = true ]; then
102
+ echo -e "${CYAN}Running typecheck...${NC}"
103
+ if ! npx tsc --noEmit 2>&1 | head -30; then
104
+ has_errors=true
105
+ else
106
+ echo -e "${GREEN}✓ Types OK${NC}"
107
+ fi
108
+ fi
109
+
110
+ # ESLint
111
+ if [ "$RUN_LINT" = true ] && [ -n "$file" ]; then
112
+ echo -e "${CYAN}Running eslint...${NC}"
113
+ if ! npx eslint "$file" --fix 2>&1 | head -20; then
114
+ has_errors=true
115
+ else
116
+ echo -e "${GREEN}✓ Lint OK${NC}"
117
+ fi
118
+ fi
119
+
120
+ if [ "$has_errors" = true ]; then
121
+ echo -e "${RED}━━━ Errors Found ━━━${NC}"
122
+ else
123
+ echo -e "${GREEN}━━━ All Checks Passed ━━━${NC}"
124
+ fi
125
+ echo ""
126
+ }
127
+
128
+ start_watching() {
129
+ echo -e "${CYAN}"
130
+ echo "╔═══════════════════════════════════════════════════════════════╗"
131
+ echo "║ Wogi Flow - File Watcher ║"
132
+ echo "╚═══════════════════════════════════════════════════════════════╝"
133
+ echo -e "${NC}"
134
+ echo ""
135
+ echo "Watching: $WATCH_DIR"
136
+ echo "Extensions: $EXTENSIONS"
137
+ echo "Typecheck: $RUN_TYPES"
138
+ echo "Lint: $RUN_LINT"
139
+ echo ""
140
+ echo -e "${DIM}Press Ctrl+C to stop${NC}"
141
+ echo ""
142
+
143
+ case $WATCHER in
144
+ nodemon)
145
+ npx nodemon \
146
+ --watch "$WATCH_DIR" \
147
+ --ext "$EXTENSIONS" \
148
+ --exec "bash -c 'echo \"Change detected\" && npx tsc --noEmit 2>&1 | head -20 && echo \"\" '"
149
+ ;;
150
+ fswatch)
151
+ fswatch -r "$WATCH_DIR" | while read file; do
152
+ if [[ "$file" =~ \.(ts|tsx|js|jsx)$ ]]; then
153
+ run_validation "$file"
154
+ fi
155
+ done
156
+ ;;
157
+ inotify)
158
+ inotifywait -m -r -e modify,create "$WATCH_DIR" --format '%w%f' | while read file; do
159
+ if [[ "$file" =~ \.(ts|tsx|js|jsx)$ ]]; then
160
+ run_validation "$file"
161
+ fi
162
+ done
163
+ ;;
164
+ esac
165
+ }
166
+
167
+ check_requirements
168
+ start_watching
@@ -0,0 +1,521 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Wogi Flow - Modular Workflow Steps
5
+ *
6
+ * Configurable plug-in steps that run at various points in the task workflow.
7
+ * Developers can enable/disable steps via config or interactive setup.
8
+ *
9
+ * Usage:
10
+ * const { runSteps, listSteps, getStepConfig } = require('./flow-workflow-steps');
11
+ * await runSteps('afterTask', { taskId: 'TASK-001', files: [...] });
12
+ */
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const { getProjectRoot, colors, getConfig } = require('./flow-utils');
17
+
18
+ const PROJECT_ROOT = getProjectRoot();
19
+
20
+ // ============================================================
21
+ // Step Registry - All available workflow steps
22
+ // ============================================================
23
+
24
+ /**
25
+ * Step definitions with metadata
26
+ * Each step has:
27
+ * - name: Unique identifier
28
+ * - description: Human-readable description
29
+ * - category: Grouping for UI
30
+ * - defaultMode: Default mode (block/warn/prompt/auto)
31
+ * - defaultWhen: Default execution point
32
+ * - defaultEnabled: Whether enabled by default
33
+ * - handler: Function that executes the step
34
+ * - configKey: Legacy config key for backwards compatibility
35
+ */
36
+ const STEP_REGISTRY = {
37
+ regressionTest: {
38
+ name: 'regressionTest',
39
+ description: 'Test random completed tasks to catch regressions',
40
+ category: 'testing',
41
+ defaultMode: 'warn',
42
+ defaultWhen: 'afterTask',
43
+ defaultEnabled: true,
44
+ configKey: 'regressionTesting',
45
+ handlerPath: './flow-step-regression',
46
+ },
47
+ browserTest: {
48
+ name: 'browserTest',
49
+ description: 'Suggest browser tests for UI changes',
50
+ category: 'testing',
51
+ defaultMode: 'prompt',
52
+ defaultWhen: 'afterTask',
53
+ defaultEnabled: true,
54
+ triggerFor: ['*.tsx', '*.jsx', '*.vue', '*.svelte'],
55
+ configKey: 'browserTesting',
56
+ handlerPath: './flow-step-browser',
57
+ },
58
+ securityScan: {
59
+ name: 'securityScan',
60
+ description: 'Run npm audit and security checks',
61
+ category: 'quality',
62
+ defaultMode: 'block',
63
+ defaultWhen: 'beforeCommit',
64
+ defaultEnabled: true,
65
+ configKey: 'security',
66
+ handlerPath: './flow-step-security',
67
+ },
68
+ updateKnowledgeBase: {
69
+ name: 'updateKnowledgeBase',
70
+ description: 'Document learnings in knowledge base',
71
+ category: 'documentation',
72
+ defaultMode: 'prompt',
73
+ defaultWhen: 'afterTask',
74
+ defaultEnabled: false,
75
+ handlerPath: './flow-step-knowledge',
76
+ },
77
+ updateChangelog: {
78
+ name: 'updateChangelog',
79
+ description: 'Add entry to CHANGELOG.md',
80
+ category: 'documentation',
81
+ defaultMode: 'prompt',
82
+ defaultWhen: 'beforeCommit',
83
+ defaultEnabled: false,
84
+ handlerPath: './flow-step-changelog',
85
+ },
86
+ codeComplexityCheck: {
87
+ name: 'codeComplexityCheck',
88
+ description: 'Flag functions exceeding complexity threshold',
89
+ category: 'quality',
90
+ defaultMode: 'warn',
91
+ defaultWhen: 'afterTask',
92
+ defaultEnabled: false,
93
+ defaultConfig: { threshold: 10 },
94
+ handlerPath: './flow-step-complexity',
95
+ },
96
+ coverageCheck: {
97
+ name: 'coverageCheck',
98
+ description: 'Ensure test coverage meets threshold',
99
+ category: 'quality',
100
+ defaultMode: 'warn',
101
+ defaultWhen: 'beforeCommit',
102
+ defaultEnabled: false,
103
+ defaultConfig: { minCoverage: 80 },
104
+ handlerPath: './flow-step-coverage',
105
+ },
106
+ codeSimplifier: {
107
+ name: 'codeSimplifier',
108
+ description: 'AI-powered code simplification suggestions (qualitative)',
109
+ category: 'quality',
110
+ defaultMode: 'prompt',
111
+ defaultWhen: 'afterTask',
112
+ defaultEnabled: false,
113
+ defaultConfig: {
114
+ maxFunctionLines: 50,
115
+ maxNestingDepth: 3,
116
+ suggestExtraction: true,
117
+ },
118
+ handlerPath: './flow-step-simplifier',
119
+ },
120
+ codeReview: {
121
+ name: 'codeReview',
122
+ description: 'Hybrid code review (multi-agent for big/high-risk)',
123
+ category: 'quality',
124
+ defaultMode: 'warn',
125
+ defaultWhen: 'afterTask',
126
+ defaultEnabled: false,
127
+ defaultConfig: {
128
+ multiAgentThreshold: 5,
129
+ highRiskPatterns: ['auth', 'payment', 'security', 'crypto'],
130
+ confidenceThreshold: 80,
131
+ },
132
+ handlerPath: './flow-step-review',
133
+ },
134
+ prTestAnalyzer: {
135
+ name: 'prTestAnalyzer',
136
+ description: 'Analyze test coverage and quality for modified files',
137
+ category: 'testing',
138
+ defaultMode: 'warn',
139
+ defaultWhen: 'beforeCommit',
140
+ defaultEnabled: true,
141
+ defaultConfig: {
142
+ checkCoverage: true,
143
+ checkQuality: true,
144
+ minCoverageForModified: 70,
145
+ },
146
+ handlerPath: './flow-step-pr-tests',
147
+ },
148
+ silentFailureHunter: {
149
+ name: 'silentFailureHunter',
150
+ description: 'Detect empty catch blocks and swallowed errors',
151
+ category: 'quality',
152
+ defaultMode: 'warn',
153
+ defaultWhen: 'afterTask',
154
+ defaultEnabled: false,
155
+ defaultConfig: {
156
+ checkEmptyCatch: true,
157
+ checkLogOnlyCatch: true,
158
+ checkUnhandledAsync: true,
159
+ checkPromiseChains: true,
160
+ },
161
+ handlerPath: './flow-step-silent-failures',
162
+ },
163
+ commentAnalyzer: {
164
+ name: 'commentAnalyzer',
165
+ description: 'Analyze comment quality (TODOs, stale, JSDoc accuracy)',
166
+ category: 'quality',
167
+ defaultMode: 'warn',
168
+ defaultWhen: 'afterTask',
169
+ defaultEnabled: false,
170
+ defaultConfig: {
171
+ flagTodo: true,
172
+ flagFixme: true,
173
+ checkJsdoc: true,
174
+ flagCommentedCode: true,
175
+ flagStale: true,
176
+ },
177
+ handlerPath: './flow-step-comments',
178
+ },
179
+ };
180
+
181
+ // Lazy load handlers to avoid circular dependencies
182
+ function getHandler(stepName) {
183
+ const step = STEP_REGISTRY[stepName];
184
+ if (!step) return null;
185
+
186
+ // Lazy load the handler from handlerPath
187
+ if (!step._handler && step.handlerPath) {
188
+ try {
189
+ step._handler = require(step.handlerPath);
190
+ } catch (err) {
191
+ // Handler not implemented yet
192
+ if (process.env.DEBUG) {
193
+ console.warn(`[DEBUG] Failed to load handler for ${stepName}: ${err.message}`);
194
+ }
195
+ return null;
196
+ }
197
+ }
198
+ return step._handler;
199
+ }
200
+
201
+ // ============================================================
202
+ // Configuration Resolution
203
+ // ============================================================
204
+
205
+ /**
206
+ * Get step configuration, merging defaults with user config
207
+ * Supports legacy config keys for backwards compatibility
208
+ */
209
+ function getStepConfig(stepName) {
210
+ const config = getConfig();
211
+ const stepDef = STEP_REGISTRY[stepName];
212
+
213
+ if (!stepDef) {
214
+ return null;
215
+ }
216
+
217
+ // Check new workflowSteps config first
218
+ const workflowSteps = config.workflowSteps || {};
219
+ const userConfig = workflowSteps[stepName] || {};
220
+
221
+ // Fall back to legacy config if workflowSteps not defined for this step
222
+ let legacyEnabled = null;
223
+ let legacyConfig = {};
224
+
225
+ if (stepDef.configKey && !workflowSteps[stepName]) {
226
+ const legacySection = config[stepDef.configKey];
227
+ if (legacySection) {
228
+ legacyEnabled = legacySection.enabled !== false;
229
+ legacyConfig = legacySection;
230
+ }
231
+ }
232
+
233
+ return {
234
+ enabled: userConfig.enabled ?? legacyEnabled ?? stepDef.defaultEnabled,
235
+ mode: userConfig.mode || stepDef.defaultMode,
236
+ when: userConfig.when || stepDef.defaultWhen,
237
+ triggerFor: userConfig.triggerFor || stepDef.triggerFor,
238
+ config: { ...stepDef.defaultConfig, ...legacyConfig, ...userConfig.config },
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Get all steps with their resolved configuration
244
+ */
245
+ function getAllSteps() {
246
+ const steps = {};
247
+ for (const stepName of Object.keys(STEP_REGISTRY)) {
248
+ steps[stepName] = {
249
+ ...STEP_REGISTRY[stepName],
250
+ ...getStepConfig(stepName),
251
+ };
252
+ }
253
+ return steps;
254
+ }
255
+
256
+ // ============================================================
257
+ // Step Execution
258
+ // ============================================================
259
+
260
+ /**
261
+ * Run all enabled steps for a given execution point
262
+ *
263
+ * @param {string} when - Execution point: 'afterTask', 'beforeCommit', 'afterCommit', 'onSessionEnd'
264
+ * @param {object} context - Context object with taskId, files, etc.
265
+ * @returns {object} - { success: boolean, results: { stepName: { passed, message, blocked } } }
266
+ */
267
+ async function runSteps(when, context = {}) {
268
+ const results = {};
269
+ let allPassed = true;
270
+ let blocked = false;
271
+
272
+ const allSteps = getAllSteps();
273
+
274
+ for (const [stepName, step] of Object.entries(allSteps)) {
275
+ // Skip disabled steps
276
+ if (!step.enabled) {
277
+ continue;
278
+ }
279
+
280
+ // Skip steps not for this execution point
281
+ if (step.when !== when) {
282
+ continue;
283
+ }
284
+
285
+ // Check file trigger patterns
286
+ if (step.triggerFor && context.files) {
287
+ const hasMatchingFile = context.files.some(file => {
288
+ return step.triggerFor.some(pattern => {
289
+ const ext = pattern.replace('*', '');
290
+ return file.endsWith(ext);
291
+ });
292
+ });
293
+ if (!hasMatchingFile) {
294
+ continue;
295
+ }
296
+ }
297
+
298
+ // Get handler
299
+ const handler = getHandler(stepName);
300
+ if (!handler || typeof handler.run !== 'function') {
301
+ results[stepName] = { passed: true, skipped: true, message: 'Handler not implemented' };
302
+ continue;
303
+ }
304
+
305
+ // Execute step
306
+ console.log(colors.cyan + `\n[${stepName}] ` + colors.reset + step.description);
307
+
308
+ try {
309
+ const result = await handler.run({
310
+ ...context,
311
+ stepConfig: step.config,
312
+ mode: step.mode,
313
+ });
314
+
315
+ results[stepName] = result;
316
+
317
+ // Handle result based on mode
318
+ if (!result.passed) {
319
+ if (step.mode === 'block') {
320
+ console.log(colors.red + ` BLOCKED: ${result.message}` + colors.reset);
321
+ blocked = true;
322
+ allPassed = false;
323
+ } else if (step.mode === 'warn') {
324
+ console.log(colors.yellow + ` WARNING: ${result.message}` + colors.reset);
325
+ // Warnings don't block, but track that something failed
326
+ } else if (step.mode === 'prompt') {
327
+ // Prompts are handled by the handler itself
328
+ }
329
+ } else {
330
+ console.log(colors.green + ` PASSED` + colors.reset);
331
+ }
332
+
333
+ } catch (error) {
334
+ results[stepName] = { passed: false, error: error.message };
335
+ console.log(colors.red + ` ERROR: ${error.message}` + colors.reset);
336
+
337
+ if (step.mode === 'block') {
338
+ blocked = true;
339
+ allPassed = false;
340
+ }
341
+ }
342
+ }
343
+
344
+ return { success: allPassed, blocked, results };
345
+ }
346
+
347
+ // ============================================================
348
+ // CLI Helpers
349
+ // ============================================================
350
+
351
+ /**
352
+ * List all steps with their status
353
+ */
354
+ function listSteps() {
355
+ const allSteps = getAllSteps();
356
+ const byCategory = {};
357
+
358
+ for (const [stepName, step] of Object.entries(allSteps)) {
359
+ const category = step.category || 'other';
360
+ if (!byCategory[category]) {
361
+ byCategory[category] = [];
362
+ }
363
+ byCategory[category].push({ name: stepName, ...step });
364
+ }
365
+
366
+ return byCategory;
367
+ }
368
+
369
+ /**
370
+ * Print step list to console
371
+ */
372
+ function printSteps() {
373
+ const byCategory = listSteps();
374
+
375
+ console.log(colors.cyan + '\nWorkflow Steps\n' + colors.reset);
376
+
377
+ for (const [category, steps] of Object.entries(byCategory)) {
378
+ console.log(colors.yellow + `${category.charAt(0).toUpperCase() + category.slice(1)}:` + colors.reset);
379
+
380
+ for (const step of steps) {
381
+ const status = step.enabled ? colors.green + '[ON]' : colors.dim + '[OFF]';
382
+ const mode = step.enabled ? ` (${step.mode})` : '';
383
+ console.log(` ${status}${colors.reset} ${step.name}${mode} - ${step.description}`);
384
+ }
385
+ console.log('');
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Enable a step
391
+ */
392
+ function enableStep(stepName) {
393
+ if (!STEP_REGISTRY[stepName]) {
394
+ return { success: false, error: `Unknown step: ${stepName}` };
395
+ }
396
+
397
+ const configPath = path.join(PROJECT_ROOT, '.workflow', 'config.json');
398
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
399
+
400
+ if (!config.workflowSteps) {
401
+ config.workflowSteps = {};
402
+ }
403
+
404
+ if (!config.workflowSteps[stepName]) {
405
+ config.workflowSteps[stepName] = {};
406
+ }
407
+
408
+ config.workflowSteps[stepName].enabled = true;
409
+
410
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
411
+ return { success: true };
412
+ }
413
+
414
+ /**
415
+ * Disable a step
416
+ */
417
+ function disableStep(stepName) {
418
+ if (!STEP_REGISTRY[stepName]) {
419
+ return { success: false, error: `Unknown step: ${stepName}` };
420
+ }
421
+
422
+ const configPath = path.join(PROJECT_ROOT, '.workflow', 'config.json');
423
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
424
+
425
+ if (!config.workflowSteps) {
426
+ config.workflowSteps = {};
427
+ }
428
+
429
+ if (!config.workflowSteps[stepName]) {
430
+ config.workflowSteps[stepName] = {};
431
+ }
432
+
433
+ config.workflowSteps[stepName].enabled = false;
434
+
435
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
436
+ return { success: true };
437
+ }
438
+
439
+ /**
440
+ * Get step definitions for interactive setup
441
+ */
442
+ function getStepDefinitions() {
443
+ return Object.entries(STEP_REGISTRY).map(([name, step]) => ({
444
+ name,
445
+ description: step.description,
446
+ category: step.category,
447
+ defaultEnabled: step.defaultEnabled,
448
+ defaultMode: step.defaultMode,
449
+ defaultWhen: step.defaultWhen,
450
+ defaultConfig: step.defaultConfig,
451
+ }));
452
+ }
453
+
454
+ // ============================================================
455
+ // CLI Entry Point
456
+ // ============================================================
457
+
458
+ if (require.main === module) {
459
+ const args = process.argv.slice(2);
460
+ const command = args[0];
461
+
462
+ switch (command) {
463
+ case 'list':
464
+ printSteps();
465
+ break;
466
+
467
+ case 'enable':
468
+ if (!args[1]) {
469
+ console.log(colors.red + 'Usage: flow step enable <stepName>' + colors.reset);
470
+ process.exit(1);
471
+ }
472
+ const enableResult = enableStep(args[1]);
473
+ if (enableResult.success) {
474
+ console.log(colors.green + `Enabled step: ${args[1]}` + colors.reset);
475
+ } else {
476
+ console.log(colors.red + enableResult.error + colors.reset);
477
+ process.exit(1);
478
+ }
479
+ break;
480
+
481
+ case 'disable':
482
+ if (!args[1]) {
483
+ console.log(colors.red + 'Usage: flow step disable <stepName>' + colors.reset);
484
+ process.exit(1);
485
+ }
486
+ const disableResult = disableStep(args[1]);
487
+ if (disableResult.success) {
488
+ console.log(colors.green + `Disabled step: ${args[1]}` + colors.reset);
489
+ } else {
490
+ console.log(colors.red + disableResult.error + colors.reset);
491
+ process.exit(1);
492
+ }
493
+ break;
494
+
495
+ default:
496
+ console.log(`
497
+ Workflow Steps CLI
498
+
499
+ Usage:
500
+ flow step list List all steps with status
501
+ flow step enable <name> Enable a step
502
+ flow step disable <name> Disable a step
503
+ `);
504
+ }
505
+ }
506
+
507
+ // ============================================================
508
+ // Exports
509
+ // ============================================================
510
+
511
+ module.exports = {
512
+ runSteps,
513
+ listSteps,
514
+ printSteps,
515
+ enableStep,
516
+ disableStep,
517
+ getStepConfig,
518
+ getAllSteps,
519
+ getStepDefinitions,
520
+ STEP_REGISTRY,
521
+ };