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.
- package/.workflow/agents/reviewer.md +81 -0
- package/.workflow/agents/security.md +94 -0
- package/.workflow/agents/story-writer.md +58 -0
- package/.workflow/bridges/base-bridge.js +395 -0
- package/.workflow/bridges/claude-bridge.js +434 -0
- package/.workflow/bridges/index.js +130 -0
- package/.workflow/lib/assumption-detector.js +481 -0
- package/.workflow/lib/config-substitution.js +371 -0
- package/.workflow/lib/failure-categories.js +478 -0
- package/.workflow/state/app-map.md.template +15 -0
- package/.workflow/state/architecture.md.template +24 -0
- package/.workflow/state/component-index.json.template +5 -0
- package/.workflow/state/decisions.md.template +15 -0
- package/.workflow/state/feedback-patterns.md.template +9 -0
- package/.workflow/state/knowledge-sync.json.template +6 -0
- package/.workflow/state/progress.md.template +14 -0
- package/.workflow/state/ready.json.template +7 -0
- package/.workflow/state/request-log.md.template +14 -0
- package/.workflow/state/session-state.json.template +11 -0
- package/.workflow/state/stack.md.template +33 -0
- package/.workflow/state/testing.md.template +36 -0
- package/.workflow/templates/claude-md.hbs +257 -0
- package/.workflow/templates/correction-report.md +67 -0
- package/.workflow/templates/gemini-md.hbs +52 -0
- package/README.md +1802 -0
- package/bin/flow +205 -0
- package/lib/index.js +33 -0
- package/lib/installer.js +467 -0
- package/lib/release-channel.js +269 -0
- package/lib/skill-registry.js +526 -0
- package/lib/upgrader.js +401 -0
- package/lib/utils.js +305 -0
- package/package.json +64 -0
- package/scripts/flow +985 -0
- package/scripts/flow-adaptive-learning.js +1259 -0
- package/scripts/flow-aggregate.js +488 -0
- package/scripts/flow-archive +133 -0
- package/scripts/flow-auto-context.js +1015 -0
- package/scripts/flow-auto-learn.js +615 -0
- package/scripts/flow-bridge.js +223 -0
- package/scripts/flow-browser-suggest.js +316 -0
- package/scripts/flow-bug.js +247 -0
- package/scripts/flow-cascade.js +711 -0
- package/scripts/flow-changelog +85 -0
- package/scripts/flow-checkpoint.js +483 -0
- package/scripts/flow-cli.js +403 -0
- package/scripts/flow-code-intelligence.js +760 -0
- package/scripts/flow-complexity.js +502 -0
- package/scripts/flow-config-set.js +152 -0
- package/scripts/flow-constants.js +157 -0
- package/scripts/flow-context +152 -0
- package/scripts/flow-context-init.js +482 -0
- package/scripts/flow-context-monitor.js +384 -0
- package/scripts/flow-context-scoring.js +886 -0
- package/scripts/flow-correct.js +458 -0
- package/scripts/flow-damage-control.js +985 -0
- package/scripts/flow-deps +101 -0
- package/scripts/flow-diff.js +700 -0
- package/scripts/flow-done +151 -0
- package/scripts/flow-done.js +489 -0
- package/scripts/flow-durable-session.js +1541 -0
- package/scripts/flow-entropy-monitor.js +345 -0
- package/scripts/flow-export-profile +349 -0
- package/scripts/flow-export-scanner.js +1046 -0
- package/scripts/flow-figma-confirm.js +400 -0
- package/scripts/flow-figma-extract.js +496 -0
- package/scripts/flow-figma-generate.js +683 -0
- package/scripts/flow-figma-index.js +909 -0
- package/scripts/flow-figma-match.js +617 -0
- package/scripts/flow-figma-mcp-server.js +518 -0
- package/scripts/flow-figma-pipeline.js +414 -0
- package/scripts/flow-file-ops.js +301 -0
- package/scripts/flow-gate-confidence.js +825 -0
- package/scripts/flow-guided-edit.js +659 -0
- package/scripts/flow-health +185 -0
- package/scripts/flow-health.js +413 -0
- package/scripts/flow-hooks.js +556 -0
- package/scripts/flow-http-client.js +249 -0
- package/scripts/flow-hybrid-detect.js +167 -0
- package/scripts/flow-hybrid-interactive.js +591 -0
- package/scripts/flow-hybrid-test.js +152 -0
- package/scripts/flow-import-profile +439 -0
- package/scripts/flow-init +253 -0
- package/scripts/flow-instruction-richness.js +827 -0
- package/scripts/flow-jira-integration.js +579 -0
- package/scripts/flow-knowledge-router.js +522 -0
- package/scripts/flow-knowledge-sync.js +589 -0
- package/scripts/flow-linear-integration.js +631 -0
- package/scripts/flow-links.js +774 -0
- package/scripts/flow-log-manager.js +559 -0
- package/scripts/flow-loop-enforcer.js +1246 -0
- package/scripts/flow-loop-retry-learning.js +630 -0
- package/scripts/flow-lsp.js +923 -0
- package/scripts/flow-map-index +348 -0
- package/scripts/flow-map-sync +201 -0
- package/scripts/flow-memory-blocks.js +668 -0
- package/scripts/flow-memory-compactor.js +350 -0
- package/scripts/flow-memory-db.js +1110 -0
- package/scripts/flow-memory-sync.js +484 -0
- package/scripts/flow-metrics.js +353 -0
- package/scripts/flow-migrate-ids.js +370 -0
- package/scripts/flow-model-adapter.js +802 -0
- package/scripts/flow-model-router.js +884 -0
- package/scripts/flow-models.js +1231 -0
- package/scripts/flow-morning.js +517 -0
- package/scripts/flow-multi-approach.js +660 -0
- package/scripts/flow-new-feature +86 -0
- package/scripts/flow-onboard +1042 -0
- package/scripts/flow-orchestrate-llm.js +459 -0
- package/scripts/flow-orchestrate.js +3592 -0
- package/scripts/flow-output.js +123 -0
- package/scripts/flow-parallel-detector.js +399 -0
- package/scripts/flow-parallel-dispatch.js +987 -0
- package/scripts/flow-parallel.js +428 -0
- package/scripts/flow-pattern-enforcer.js +600 -0
- package/scripts/flow-prd-manager.js +282 -0
- package/scripts/flow-progress.js +323 -0
- package/scripts/flow-project-analyzer.js +975 -0
- package/scripts/flow-prompt-composer.js +487 -0
- package/scripts/flow-providers.js +1381 -0
- package/scripts/flow-queue.js +308 -0
- package/scripts/flow-ready +82 -0
- package/scripts/flow-ready.js +189 -0
- package/scripts/flow-regression.js +396 -0
- package/scripts/flow-response-parser.js +450 -0
- package/scripts/flow-resume.js +284 -0
- package/scripts/flow-rules-sync.js +439 -0
- package/scripts/flow-run-trace.js +718 -0
- package/scripts/flow-safety.js +587 -0
- package/scripts/flow-search +104 -0
- package/scripts/flow-security.js +481 -0
- package/scripts/flow-session-end +106 -0
- package/scripts/flow-session-end.js +437 -0
- package/scripts/flow-session-state.js +671 -0
- package/scripts/flow-setup-hooks +216 -0
- package/scripts/flow-setup-hooks.js +377 -0
- package/scripts/flow-skill-create.js +329 -0
- package/scripts/flow-skill-creator.js +572 -0
- package/scripts/flow-skill-generator.js +1046 -0
- package/scripts/flow-skill-learn.js +880 -0
- package/scripts/flow-skill-matcher.js +578 -0
- package/scripts/flow-spec-generator.js +820 -0
- package/scripts/flow-stack-wizard.js +895 -0
- package/scripts/flow-standup +162 -0
- package/scripts/flow-start +74 -0
- package/scripts/flow-start.js +235 -0
- package/scripts/flow-status +110 -0
- package/scripts/flow-status.js +301 -0
- package/scripts/flow-step-browser.js +83 -0
- package/scripts/flow-step-changelog.js +217 -0
- package/scripts/flow-step-comments.js +306 -0
- package/scripts/flow-step-complexity.js +234 -0
- package/scripts/flow-step-coverage.js +218 -0
- package/scripts/flow-step-knowledge.js +193 -0
- package/scripts/flow-step-pr-tests.js +364 -0
- package/scripts/flow-step-regression.js +89 -0
- package/scripts/flow-step-review.js +516 -0
- package/scripts/flow-step-security.js +162 -0
- package/scripts/flow-step-silent-failures.js +290 -0
- package/scripts/flow-step-simplifier.js +346 -0
- package/scripts/flow-story +105 -0
- package/scripts/flow-story.js +500 -0
- package/scripts/flow-suspend.js +252 -0
- package/scripts/flow-sync-daemon.js +654 -0
- package/scripts/flow-task-analyzer.js +606 -0
- package/scripts/flow-team-dashboard.js +748 -0
- package/scripts/flow-team-sync.js +752 -0
- package/scripts/flow-team.js +977 -0
- package/scripts/flow-tech-options.js +528 -0
- package/scripts/flow-templates.js +812 -0
- package/scripts/flow-tiered-learning.js +728 -0
- package/scripts/flow-trace +204 -0
- package/scripts/flow-transcript-chunking.js +1106 -0
- package/scripts/flow-transcript-digest.js +7918 -0
- package/scripts/flow-transcript-language.js +465 -0
- package/scripts/flow-transcript-parsing.js +1085 -0
- package/scripts/flow-transcript-stories.js +2194 -0
- package/scripts/flow-update-map +224 -0
- package/scripts/flow-utils.js +2242 -0
- package/scripts/flow-verification.js +644 -0
- package/scripts/flow-verify.js +1177 -0
- package/scripts/flow-voice-input.js +638 -0
- package/scripts/flow-watch +168 -0
- package/scripts/flow-workflow-steps.js +521 -0
- package/scripts/flow-workflow.js +1029 -0
- package/scripts/flow-worktree.js +489 -0
- package/scripts/hooks/adapters/base-adapter.js +102 -0
- package/scripts/hooks/adapters/claude-code.js +359 -0
- package/scripts/hooks/adapters/index.js +79 -0
- package/scripts/hooks/core/component-check.js +341 -0
- package/scripts/hooks/core/index.js +35 -0
- package/scripts/hooks/core/loop-check.js +241 -0
- package/scripts/hooks/core/session-context.js +294 -0
- package/scripts/hooks/core/task-gate.js +177 -0
- package/scripts/hooks/core/validation.js +230 -0
- package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
- package/scripts/hooks/entry/claude-code/session-end.js +87 -0
- package/scripts/hooks/entry/claude-code/session-start.js +46 -0
- package/scripts/hooks/entry/claude-code/stop.js +43 -0
- package/scripts/postinstall.js +139 -0
- package/templates/browser-test-flow.json +56 -0
- package/templates/bug-report.md +43 -0
- package/templates/component-detail.md +42 -0
- package/templates/component.stories.tsx +49 -0
- package/templates/context/constraints.md +83 -0
- package/templates/context/conventions.md +177 -0
- package/templates/context/stack.md +60 -0
- package/templates/correction-report.md +90 -0
- package/templates/feature-proposal.md +35 -0
- package/templates/hybrid/_base.md +254 -0
- package/templates/hybrid/_patterns.md +45 -0
- package/templates/hybrid/create-component.md +127 -0
- package/templates/hybrid/create-file.md +56 -0
- package/templates/hybrid/create-hook.md +145 -0
- package/templates/hybrid/create-service.md +70 -0
- package/templates/hybrid/fix-bug.md +33 -0
- package/templates/hybrid/modify-file.md +55 -0
- package/templates/story.md +68 -0
- package/templates/task.json +56 -0
- 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
|
+
};
|