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,216 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Wogi Flow - Setup Git Hooks
|
|
4
|
+
# Installs optional pre-commit hooks to enforce workflow rules
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
WORKFLOW_DIR=".workflow"
|
|
9
|
+
|
|
10
|
+
# Colors
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
RED='\033[0;31m'
|
|
14
|
+
CYAN='\033[0;36m'
|
|
15
|
+
NC='\033[0m'
|
|
16
|
+
|
|
17
|
+
show_help() {
|
|
18
|
+
echo "Setup Git Hooks"
|
|
19
|
+
echo ""
|
|
20
|
+
echo "Usage: flow setup-hooks [options]"
|
|
21
|
+
echo ""
|
|
22
|
+
echo "Options:"
|
|
23
|
+
echo " install Install pre-commit hooks"
|
|
24
|
+
echo " uninstall Remove pre-commit hooks"
|
|
25
|
+
echo " status Check if hooks are installed"
|
|
26
|
+
echo ""
|
|
27
|
+
echo "Hooks enforce:"
|
|
28
|
+
echo " • request-log.md has been updated"
|
|
29
|
+
echo " • app-map.md updated if new components"
|
|
30
|
+
echo " • No console.log in production code"
|
|
31
|
+
echo " • Tests pass (if configured in config.json)"
|
|
32
|
+
echo " • Skill learning extraction (if skillLearning.enabled)"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
install_hooks() {
|
|
36
|
+
if [ ! -d ".git" ]; then
|
|
37
|
+
echo -e "${RED}Error: Not a git repository${NC}"
|
|
38
|
+
exit 1
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
mkdir -p .git/hooks
|
|
42
|
+
|
|
43
|
+
# Create pre-commit hook
|
|
44
|
+
cat > .git/hooks/pre-commit << 'HOOK'
|
|
45
|
+
#!/bin/bash
|
|
46
|
+
|
|
47
|
+
# Wogi Flow Pre-commit Hook
|
|
48
|
+
# Enforces workflow rules before commits
|
|
49
|
+
|
|
50
|
+
WORKFLOW_DIR=".workflow"
|
|
51
|
+
RED='\033[0;31m'
|
|
52
|
+
GREEN='\033[0;32m'
|
|
53
|
+
YELLOW='\033[1;33m'
|
|
54
|
+
NC='\033[0m'
|
|
55
|
+
|
|
56
|
+
echo "Running Wogi Flow pre-commit checks..."
|
|
57
|
+
|
|
58
|
+
failed=0
|
|
59
|
+
|
|
60
|
+
# Check 1: request-log.md was modified (if other files changed)
|
|
61
|
+
staged_files=$(git diff --cached --name-only)
|
|
62
|
+
non_workflow_files=$(echo "$staged_files" | grep -v "^\.workflow/" | grep -v "^CLAUDE.md" || true)
|
|
63
|
+
|
|
64
|
+
if [ -n "$non_workflow_files" ]; then
|
|
65
|
+
if ! echo "$staged_files" | grep -q "request-log.md"; then
|
|
66
|
+
echo -e "${YELLOW}⚠ Warning: Code changed but request-log.md not updated${NC}"
|
|
67
|
+
echo " Consider adding a log entry for this change."
|
|
68
|
+
# Warning only, don't fail
|
|
69
|
+
else
|
|
70
|
+
echo -e "${GREEN}✓${NC} request-log.md updated"
|
|
71
|
+
fi
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# Check 2: No console.log in staged JS/TS files (warning only)
|
|
75
|
+
js_files=$(echo "$staged_files" | grep -E '\.(js|ts|jsx|tsx)$' || true)
|
|
76
|
+
if [ -n "$js_files" ]; then
|
|
77
|
+
console_logs=$(git diff --cached -- $js_files | grep -E '^\+.*console\.(log|debug)' || true)
|
|
78
|
+
if [ -n "$console_logs" ]; then
|
|
79
|
+
echo -e "${YELLOW}⚠ Warning: console.log found in staged files${NC}"
|
|
80
|
+
echo "$console_logs" | head -5
|
|
81
|
+
# Warning only
|
|
82
|
+
fi
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# Check 3: Run tests if configured
|
|
86
|
+
if [ -f "$WORKFLOW_DIR/config.json" ]; then
|
|
87
|
+
run_tests=$(CONFIG_FILE="$WORKFLOW_DIR/config.json" python3 -c "
|
|
88
|
+
import json, os
|
|
89
|
+
with open(os.environ['CONFIG_FILE']) as f:
|
|
90
|
+
config = json.load(f)
|
|
91
|
+
print(config.get('testing', {}).get('runBeforeCommit', False))
|
|
92
|
+
" 2>/dev/null || echo "False")
|
|
93
|
+
|
|
94
|
+
if [ "$run_tests" = "True" ]; then
|
|
95
|
+
echo "Running tests..."
|
|
96
|
+
if npm test --silent 2>/dev/null; then
|
|
97
|
+
echo -e "${GREEN}✓${NC} Tests passed"
|
|
98
|
+
else
|
|
99
|
+
echo -e "${RED}✗ Tests failed${NC}"
|
|
100
|
+
failed=1
|
|
101
|
+
fi
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# Check 4: Lint if configured
|
|
106
|
+
if [ -f "package.json" ] && grep -q '"lint"' package.json 2>/dev/null; then
|
|
107
|
+
staged_code=$(echo "$staged_files" | grep -E '\.(js|ts|jsx|tsx|vue)$' || true)
|
|
108
|
+
if [ -n "$staged_code" ]; then
|
|
109
|
+
# Only lint staged files
|
|
110
|
+
if command -v npx &> /dev/null && [ -f ".eslintrc.js" ] || [ -f ".eslintrc.json" ] || [ -f ".eslintrc" ]; then
|
|
111
|
+
echo "Linting staged files..."
|
|
112
|
+
if echo "$staged_code" | xargs npx eslint --quiet 2>/dev/null; then
|
|
113
|
+
echo -e "${GREEN}✓${NC} Lint passed"
|
|
114
|
+
else
|
|
115
|
+
echo -e "${YELLOW}⚠${NC} Lint warnings (not blocking)"
|
|
116
|
+
fi
|
|
117
|
+
fi
|
|
118
|
+
fi
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# Check 5: Skill Learning (extract learnings before commit)
|
|
122
|
+
if [ -f "$WORKFLOW_DIR/config.json" ]; then
|
|
123
|
+
skill_learning=$(CONFIG_FILE="$WORKFLOW_DIR/config.json" python3 -c "
|
|
124
|
+
import json, os
|
|
125
|
+
with open(os.environ['CONFIG_FILE']) as f:
|
|
126
|
+
config = json.load(f)
|
|
127
|
+
sl = config.get('skillLearning', {})
|
|
128
|
+
enabled = sl.get('enabled', False) and sl.get('autoExtract', False)
|
|
129
|
+
trigger = sl.get('triggers', {}).get('onCommit', True)
|
|
130
|
+
print('True' if enabled and trigger else 'False')
|
|
131
|
+
" 2>/dev/null || echo "False")
|
|
132
|
+
|
|
133
|
+
if [ "$skill_learning" = "True" ]; then
|
|
134
|
+
echo "📚 Extracting skill learnings..."
|
|
135
|
+
if command -v node &> /dev/null && [ -f "scripts/flow-skill-learn.js" ]; then
|
|
136
|
+
node scripts/flow-skill-learn.js --trigger=commit 2>/dev/null || true
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
if [ $failed -eq 1 ]; then
|
|
142
|
+
echo ""
|
|
143
|
+
echo -e "${RED}Pre-commit checks failed. Fix issues or use --no-verify to bypass.${NC}"
|
|
144
|
+
exit 1
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
echo -e "${GREEN}✓ Pre-commit checks passed${NC}"
|
|
148
|
+
exit 0
|
|
149
|
+
HOOK
|
|
150
|
+
|
|
151
|
+
chmod +x .git/hooks/pre-commit
|
|
152
|
+
|
|
153
|
+
echo -e "${GREEN}✓ Pre-commit hook installed${NC}"
|
|
154
|
+
echo ""
|
|
155
|
+
echo "The hook will check:"
|
|
156
|
+
echo " • request-log.md updates (warning)"
|
|
157
|
+
echo " • console.log statements (warning)"
|
|
158
|
+
echo " • Tests (if runBeforeCommit: true in config.json)"
|
|
159
|
+
echo " • Lint (if eslint configured)"
|
|
160
|
+
echo ""
|
|
161
|
+
echo "To bypass: git commit --no-verify"
|
|
162
|
+
echo "To remove: ./scripts/flow setup-hooks uninstall"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
uninstall_hooks() {
|
|
166
|
+
if [ -f ".git/hooks/pre-commit" ]; then
|
|
167
|
+
# Check if it's our hook
|
|
168
|
+
if grep -q "Wogi Flow" .git/hooks/pre-commit 2>/dev/null; then
|
|
169
|
+
rm .git/hooks/pre-commit
|
|
170
|
+
echo -e "${GREEN}✓ Pre-commit hook removed${NC}"
|
|
171
|
+
else
|
|
172
|
+
echo -e "${YELLOW}Pre-commit hook exists but wasn't installed by Wogi Flow${NC}"
|
|
173
|
+
echo "Remove manually if desired: rm .git/hooks/pre-commit"
|
|
174
|
+
fi
|
|
175
|
+
else
|
|
176
|
+
echo "No pre-commit hook installed"
|
|
177
|
+
fi
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
check_status() {
|
|
181
|
+
echo -e "${CYAN}Hook Status${NC}"
|
|
182
|
+
echo ""
|
|
183
|
+
|
|
184
|
+
if [ ! -d ".git" ]; then
|
|
185
|
+
echo -e "${YELLOW}Not a git repository${NC}"
|
|
186
|
+
exit 0
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
if [ -f ".git/hooks/pre-commit" ]; then
|
|
190
|
+
if grep -q "Wogi Flow" .git/hooks/pre-commit 2>/dev/null; then
|
|
191
|
+
echo -e "${GREEN}✓${NC} Wogi Flow pre-commit hook installed"
|
|
192
|
+
else
|
|
193
|
+
echo -e "${YELLOW}○${NC} Pre-commit hook exists (not Wogi Flow)"
|
|
194
|
+
fi
|
|
195
|
+
else
|
|
196
|
+
echo -e "${YELLOW}○${NC} No pre-commit hook installed"
|
|
197
|
+
fi
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
case "${1:-}" in
|
|
201
|
+
install)
|
|
202
|
+
install_hooks
|
|
203
|
+
;;
|
|
204
|
+
uninstall)
|
|
205
|
+
uninstall_hooks
|
|
206
|
+
;;
|
|
207
|
+
status)
|
|
208
|
+
check_status
|
|
209
|
+
;;
|
|
210
|
+
help|--help|-h)
|
|
211
|
+
show_help
|
|
212
|
+
;;
|
|
213
|
+
*)
|
|
214
|
+
show_help
|
|
215
|
+
;;
|
|
216
|
+
esac
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wogi Flow - Git Hooks Setup
|
|
5
|
+
*
|
|
6
|
+
* Installs git hooks for automatic workflow integration:
|
|
7
|
+
* - pre-commit: Optionally runs component index scan
|
|
8
|
+
* - post-commit: Optionally syncs rules from decisions.md
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node scripts/flow-setup-hooks.js # Install hooks
|
|
12
|
+
* node scripts/flow-setup-hooks.js --remove # Remove hooks
|
|
13
|
+
* node scripts/flow-setup-hooks.js --status # Check hook status
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const {
|
|
19
|
+
getProjectRoot,
|
|
20
|
+
getConfig,
|
|
21
|
+
color,
|
|
22
|
+
success,
|
|
23
|
+
warn,
|
|
24
|
+
error
|
|
25
|
+
} = require('./flow-utils');
|
|
26
|
+
|
|
27
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
28
|
+
const GIT_DIR = path.join(PROJECT_ROOT, '.git');
|
|
29
|
+
const HOOKS_DIR = path.join(GIT_DIR, 'hooks');
|
|
30
|
+
|
|
31
|
+
// Hook marker to identify our managed hooks
|
|
32
|
+
const HOOK_MARKER = '# WOGI_FLOW_MANAGED_HOOK';
|
|
33
|
+
|
|
34
|
+
// ============================================================
|
|
35
|
+
// Hook Templates
|
|
36
|
+
// ============================================================
|
|
37
|
+
|
|
38
|
+
const PRE_COMMIT_HOOK = `#!/bin/sh
|
|
39
|
+
${HOOK_MARKER}
|
|
40
|
+
# Wogi Flow Pre-commit Hook
|
|
41
|
+
# Auto-generated - do not edit manually
|
|
42
|
+
|
|
43
|
+
# Check config for what to run
|
|
44
|
+
CONFIG_FILE=".workflow/config.json"
|
|
45
|
+
|
|
46
|
+
# Function to check if a feature is enabled in config
|
|
47
|
+
check_config() {
|
|
48
|
+
local key="$1"
|
|
49
|
+
local default="$2"
|
|
50
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
51
|
+
python3 -c "
|
|
52
|
+
import json
|
|
53
|
+
try:
|
|
54
|
+
with open('$CONFIG_FILE', 'r') as f:
|
|
55
|
+
config = json.load(f)
|
|
56
|
+
keys = '$key'.split('.')
|
|
57
|
+
val = config
|
|
58
|
+
for k in keys:
|
|
59
|
+
val = val.get(k, {}) if isinstance(val, dict) else {}
|
|
60
|
+
result = val if val != {} else '$default'
|
|
61
|
+
print('true' if result == True or result == 'true' else 'false' if result == False or result == 'false' else result)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
print('$default')
|
|
64
|
+
" 2>/dev/null
|
|
65
|
+
else
|
|
66
|
+
echo "$default"
|
|
67
|
+
fi
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Run component index scan if configured
|
|
71
|
+
SCAN_ON_COMMIT=$(check_config "componentIndex.scanOn" "[]" | grep -q "preCommit" && echo "true" || echo "false")
|
|
72
|
+
if [ "$SCAN_ON_COMMIT" = "true" ]; then
|
|
73
|
+
echo "🔄 Updating component index..."
|
|
74
|
+
bash scripts/flow-map-index scan --quiet 2>/dev/null || true
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Sync rules if decisions.md was modified
|
|
78
|
+
if git diff --cached --name-only | grep -q "decisions.md"; then
|
|
79
|
+
echo "📋 Syncing rules from decisions.md..."
|
|
80
|
+
node scripts/flow-rules-sync.js 2>/dev/null || true
|
|
81
|
+
git add .claude/rules/*.md 2>/dev/null || true
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
# Continue with commit
|
|
85
|
+
exit 0
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
const POST_COMMIT_HOOK = `#!/bin/sh
|
|
89
|
+
${HOOK_MARKER}
|
|
90
|
+
# Wogi Flow Post-commit Hook
|
|
91
|
+
# Auto-generated - do not edit manually
|
|
92
|
+
|
|
93
|
+
# Optional: Log commit to request log
|
|
94
|
+
# This is disabled by default as it can be noisy
|
|
95
|
+
|
|
96
|
+
exit 0
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
// ============================================================
|
|
100
|
+
// Hook Management
|
|
101
|
+
// ============================================================
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if .git directory exists
|
|
105
|
+
*/
|
|
106
|
+
function isGitRepo() {
|
|
107
|
+
return fs.existsSync(GIT_DIR);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Check if a hook is managed by Wogi Flow
|
|
112
|
+
*/
|
|
113
|
+
function isOurHook(hookPath) {
|
|
114
|
+
if (!fs.existsSync(hookPath)) return false;
|
|
115
|
+
const content = fs.readFileSync(hookPath, 'utf-8');
|
|
116
|
+
return content.includes(HOOK_MARKER);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Install a hook
|
|
121
|
+
*/
|
|
122
|
+
function installHook(name, content) {
|
|
123
|
+
const hookPath = path.join(HOOKS_DIR, name);
|
|
124
|
+
|
|
125
|
+
// Create hooks directory if it doesn't exist
|
|
126
|
+
if (!fs.existsSync(HOOKS_DIR)) {
|
|
127
|
+
fs.mkdirSync(HOOKS_DIR, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Check if there's an existing hook
|
|
131
|
+
if (fs.existsSync(hookPath) && !isOurHook(hookPath)) {
|
|
132
|
+
const existingContent = fs.readFileSync(hookPath, 'utf-8');
|
|
133
|
+
// Backup existing hook
|
|
134
|
+
const backupPath = `${hookPath}.backup`;
|
|
135
|
+
fs.writeFileSync(backupPath, existingContent);
|
|
136
|
+
warn(`Backed up existing ${name} hook to ${name}.backup`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Write new hook
|
|
140
|
+
fs.writeFileSync(hookPath, content);
|
|
141
|
+
fs.chmodSync(hookPath, '755');
|
|
142
|
+
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Remove a hook
|
|
148
|
+
*/
|
|
149
|
+
function removeHook(name) {
|
|
150
|
+
const hookPath = path.join(HOOKS_DIR, name);
|
|
151
|
+
|
|
152
|
+
if (!fs.existsSync(hookPath)) {
|
|
153
|
+
return { existed: false };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!isOurHook(hookPath)) {
|
|
157
|
+
return { existed: true, skipped: true, reason: 'Not a Wogi Flow hook' };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
fs.unlinkSync(hookPath);
|
|
161
|
+
|
|
162
|
+
// Restore backup if exists
|
|
163
|
+
const backupPath = `${hookPath}.backup`;
|
|
164
|
+
if (fs.existsSync(backupPath)) {
|
|
165
|
+
fs.renameSync(backupPath, hookPath);
|
|
166
|
+
return { existed: true, restored: true };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return { existed: true, removed: true };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get hook status
|
|
174
|
+
*/
|
|
175
|
+
function getHookStatus(name) {
|
|
176
|
+
const hookPath = path.join(HOOKS_DIR, name);
|
|
177
|
+
|
|
178
|
+
if (!fs.existsSync(hookPath)) {
|
|
179
|
+
return { installed: false };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const isManaged = isOurHook(hookPath);
|
|
183
|
+
const stats = fs.statSync(hookPath);
|
|
184
|
+
const isExecutable = (stats.mode & 0o111) !== 0;
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
installed: true,
|
|
188
|
+
managed: isManaged,
|
|
189
|
+
executable: isExecutable,
|
|
190
|
+
path: hookPath
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ============================================================
|
|
195
|
+
// Main Commands
|
|
196
|
+
// ============================================================
|
|
197
|
+
|
|
198
|
+
function installHooks() {
|
|
199
|
+
if (!isGitRepo()) {
|
|
200
|
+
error('Not a git repository. Run this from the project root.');
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.log(color('cyan', '🪝 Installing Git Hooks'));
|
|
205
|
+
console.log('');
|
|
206
|
+
|
|
207
|
+
const results = [];
|
|
208
|
+
|
|
209
|
+
// Install pre-commit hook
|
|
210
|
+
try {
|
|
211
|
+
installHook('pre-commit', PRE_COMMIT_HOOK);
|
|
212
|
+
results.push({ name: 'pre-commit', success: true });
|
|
213
|
+
console.log(` ${color('green', '✓')} pre-commit hook installed`);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
results.push({ name: 'pre-commit', success: false, error: err.message });
|
|
216
|
+
console.log(` ${color('red', '✗')} pre-commit: ${err.message}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Install post-commit hook
|
|
220
|
+
try {
|
|
221
|
+
installHook('post-commit', POST_COMMIT_HOOK);
|
|
222
|
+
results.push({ name: 'post-commit', success: true });
|
|
223
|
+
console.log(` ${color('green', '✓')} post-commit hook installed`);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
results.push({ name: 'post-commit', success: false, error: err.message });
|
|
226
|
+
console.log(` ${color('red', '✗')} post-commit: ${err.message}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
console.log('');
|
|
230
|
+
|
|
231
|
+
const allSuccess = results.every(r => r.success);
|
|
232
|
+
if (allSuccess) {
|
|
233
|
+
success('Git hooks installed successfully');
|
|
234
|
+
console.log('');
|
|
235
|
+
console.log(color('dim', 'Configure in .workflow/config.json:'));
|
|
236
|
+
console.log(color('dim', ' componentIndex.scanOn: ["preCommit", "afterTask", "sessionStart"]'));
|
|
237
|
+
} else {
|
|
238
|
+
warn('Some hooks failed to install');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return results;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function removeHooks() {
|
|
245
|
+
if (!isGitRepo()) {
|
|
246
|
+
error('Not a git repository');
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
console.log(color('cyan', '🪝 Removing Git Hooks'));
|
|
251
|
+
console.log('');
|
|
252
|
+
|
|
253
|
+
const hooks = ['pre-commit', 'post-commit'];
|
|
254
|
+
|
|
255
|
+
for (const hook of hooks) {
|
|
256
|
+
const result = removeHook(hook);
|
|
257
|
+
if (result.skipped) {
|
|
258
|
+
console.log(` ${color('yellow', '○')} ${hook}: ${result.reason}`);
|
|
259
|
+
} else if (result.restored) {
|
|
260
|
+
console.log(` ${color('green', '✓')} ${hook} removed (backup restored)`);
|
|
261
|
+
} else if (result.removed) {
|
|
262
|
+
console.log(` ${color('green', '✓')} ${hook} removed`);
|
|
263
|
+
} else {
|
|
264
|
+
console.log(` ${color('dim', '-')} ${hook}: not installed`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.log('');
|
|
269
|
+
success('Git hooks removed');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function showStatus() {
|
|
273
|
+
if (!isGitRepo()) {
|
|
274
|
+
error('Not a git repository');
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
console.log(color('cyan', '🪝 Git Hook Status'));
|
|
279
|
+
console.log('');
|
|
280
|
+
|
|
281
|
+
const hooks = ['pre-commit', 'post-commit', 'pre-push', 'commit-msg'];
|
|
282
|
+
|
|
283
|
+
for (const hook of hooks) {
|
|
284
|
+
const status = getHookStatus(hook);
|
|
285
|
+
|
|
286
|
+
if (!status.installed) {
|
|
287
|
+
console.log(` ${color('dim', '-')} ${hook}: not installed`);
|
|
288
|
+
} else if (status.managed) {
|
|
289
|
+
console.log(` ${color('green', '✓')} ${hook}: installed (Wogi Flow managed)`);
|
|
290
|
+
} else {
|
|
291
|
+
console.log(` ${color('yellow', '○')} ${hook}: installed (external)`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
console.log('');
|
|
296
|
+
|
|
297
|
+
// Show config
|
|
298
|
+
try {
|
|
299
|
+
const config = getConfig();
|
|
300
|
+
const scanOn = config.componentIndex?.scanOn || [];
|
|
301
|
+
console.log(color('dim', 'Config: componentIndex.scanOn = ' + JSON.stringify(scanOn)));
|
|
302
|
+
} catch {
|
|
303
|
+
console.log(color('dim', 'Config: Unable to read'));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function showHelp() {
|
|
308
|
+
console.log(`
|
|
309
|
+
Wogi Flow - Git Hooks Setup
|
|
310
|
+
|
|
311
|
+
Install git hooks for automatic workflow integration.
|
|
312
|
+
|
|
313
|
+
Usage:
|
|
314
|
+
node scripts/flow-setup-hooks.js # Install hooks
|
|
315
|
+
node scripts/flow-setup-hooks.js --remove # Remove hooks
|
|
316
|
+
node scripts/flow-setup-hooks.js --status # Check status
|
|
317
|
+
node scripts/flow-setup-hooks.js --help # Show this help
|
|
318
|
+
|
|
319
|
+
Hooks installed:
|
|
320
|
+
pre-commit - Sync rules, optionally scan component index
|
|
321
|
+
post-commit - (Reserved for future use)
|
|
322
|
+
|
|
323
|
+
Configuration:
|
|
324
|
+
In .workflow/config.json, set componentIndex.scanOn to include "preCommit":
|
|
325
|
+
|
|
326
|
+
{
|
|
327
|
+
"componentIndex": {
|
|
328
|
+
"scanOn": ["sessionStart", "afterTask", "preCommit"]
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ============================================================
|
|
335
|
+
// CLI
|
|
336
|
+
// ============================================================
|
|
337
|
+
|
|
338
|
+
function main() {
|
|
339
|
+
const args = process.argv.slice(2);
|
|
340
|
+
|
|
341
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
342
|
+
showHelp();
|
|
343
|
+
process.exit(0);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (args.includes('--remove') || args.includes('--uninstall')) {
|
|
347
|
+
removeHooks();
|
|
348
|
+
process.exit(0);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (args.includes('--status')) {
|
|
352
|
+
showStatus();
|
|
353
|
+
process.exit(0);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Default: install hooks
|
|
357
|
+
installHooks();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ============================================================
|
|
361
|
+
// Exports
|
|
362
|
+
// ============================================================
|
|
363
|
+
|
|
364
|
+
module.exports = {
|
|
365
|
+
installHook,
|
|
366
|
+
removeHook,
|
|
367
|
+
getHookStatus,
|
|
368
|
+
isOurHook,
|
|
369
|
+
installHooks,
|
|
370
|
+
removeHooks,
|
|
371
|
+
showStatus,
|
|
372
|
+
HOOK_MARKER
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
if (require.main === module) {
|
|
376
|
+
main();
|
|
377
|
+
}
|