anvil-dev-framework 0.1.6
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/README.md +719 -0
- package/VERSION +1 -0
- package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
- package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
- package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
- package/docs/INSTALLATION.md +984 -0
- package/docs/anvil-hud.md +469 -0
- package/docs/anvil-init.md +255 -0
- package/docs/anvil-state.md +210 -0
- package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
- package/docs/command-reference.md +2022 -0
- package/docs/hooks-tts.md +368 -0
- package/docs/implementation-guide.md +810 -0
- package/docs/linear-github-integration.md +247 -0
- package/docs/local-issues.md +677 -0
- package/docs/patterns/README.md +419 -0
- package/docs/planning-responsibilities.md +139 -0
- package/docs/session-workflow.md +573 -0
- package/docs/simplification-plan-template.md +297 -0
- package/docs/simplification-principles.md +129 -0
- package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
- package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
- package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
- package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
- package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
- package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
- package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
- package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
- package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
- package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
- package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
- package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
- package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
- package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
- package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
- package/docs/sync.md +122 -0
- package/global/CLAUDE.md +140 -0
- package/global/agents/verify-app.md +164 -0
- package/global/commands/anvil-settings.md +527 -0
- package/global/commands/anvil-sync.md +121 -0
- package/global/commands/change.md +197 -0
- package/global/commands/clarify.md +252 -0
- package/global/commands/cleanup.md +292 -0
- package/global/commands/commit-push-pr.md +207 -0
- package/global/commands/decay-review.md +127 -0
- package/global/commands/discover.md +158 -0
- package/global/commands/doc-coverage.md +122 -0
- package/global/commands/evidence.md +307 -0
- package/global/commands/explore.md +121 -0
- package/global/commands/force-exit.md +135 -0
- package/global/commands/handoff.md +191 -0
- package/global/commands/healthcheck.md +302 -0
- package/global/commands/hud.md +84 -0
- package/global/commands/insights.md +319 -0
- package/global/commands/linear-setup.md +184 -0
- package/global/commands/lint-fix.md +198 -0
- package/global/commands/orient.md +510 -0
- package/global/commands/plan.md +228 -0
- package/global/commands/ralph.md +346 -0
- package/global/commands/ready.md +182 -0
- package/global/commands/release.md +305 -0
- package/global/commands/retro.md +96 -0
- package/global/commands/shard.md +166 -0
- package/global/commands/spec.md +227 -0
- package/global/commands/sprint.md +184 -0
- package/global/commands/tasks.md +228 -0
- package/global/commands/test-and-commit.md +151 -0
- package/global/commands/validate.md +132 -0
- package/global/commands/verify.md +251 -0
- package/global/commands/weekly-review.md +156 -0
- package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
- package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
- package/global/hooks/anvil_memory_observe.ts +322 -0
- package/global/hooks/anvil_memory_session.ts +166 -0
- package/global/hooks/anvil_memory_stop.ts +187 -0
- package/global/hooks/parse_transcript.py +116 -0
- package/global/hooks/post_merge_cleanup.sh +132 -0
- package/global/hooks/post_tool_format.sh +215 -0
- package/global/hooks/ralph_context_monitor.py +240 -0
- package/global/hooks/ralph_stop.sh +502 -0
- package/global/hooks/statusline.sh +1110 -0
- package/global/hooks/statusline_agent_sync.py +224 -0
- package/global/hooks/stop_gate.sh +250 -0
- package/global/lib/.claude/anvil-state.json +21 -0
- package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
- package/global/lib/agent_registry.py +995 -0
- package/global/lib/anvil-state.sh +435 -0
- package/global/lib/claim_service.py +515 -0
- package/global/lib/coderabbit_service.py +314 -0
- package/global/lib/config_service.py +423 -0
- package/global/lib/coordination_service.py +331 -0
- package/global/lib/doc_coverage_service.py +1305 -0
- package/global/lib/gate_logger.py +316 -0
- package/global/lib/github_service.py +310 -0
- package/global/lib/handoff_generator.py +775 -0
- package/global/lib/hygiene_service.py +712 -0
- package/global/lib/issue_models.py +257 -0
- package/global/lib/issue_provider.py +339 -0
- package/global/lib/linear_data_service.py +210 -0
- package/global/lib/linear_provider.py +987 -0
- package/global/lib/linear_provider.py.backup +671 -0
- package/global/lib/local_provider.py +486 -0
- package/global/lib/orient_fast.py +457 -0
- package/global/lib/quality_service.py +470 -0
- package/global/lib/ralph_prompt_generator.py +563 -0
- package/global/lib/ralph_state.py +1202 -0
- package/global/lib/state_manager.py +417 -0
- package/global/lib/transcript_parser.py +597 -0
- package/global/lib/verification_runner.py +557 -0
- package/global/lib/verify_iteration.py +490 -0
- package/global/lib/verify_subagent.py +250 -0
- package/global/skills/README.md +155 -0
- package/global/skills/quality-gates/SKILL.md +252 -0
- package/global/skills/skill-template/SKILL.md +109 -0
- package/global/skills/testing-strategies/SKILL.md +337 -0
- package/global/templates/CHANGE-template.md +105 -0
- package/global/templates/HANDOFF-template.md +63 -0
- package/global/templates/PLAN-template.md +111 -0
- package/global/templates/SPEC-template.md +93 -0
- package/global/templates/ralph/PROMPT.md.template +89 -0
- package/global/templates/ralph/fix_plan.md.template +31 -0
- package/global/templates/ralph/progress.txt.template +23 -0
- package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
- package/global/tests/test_doc_coverage.py +520 -0
- package/global/tests/test_issue_models.py +299 -0
- package/global/tests/test_local_provider.py +323 -0
- package/global/tools/README.md +178 -0
- package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
- package/global/tools/anvil-hud.py +3622 -0
- package/global/tools/anvil-hud.py.bak +3318 -0
- package/global/tools/anvil-issue.py +432 -0
- package/global/tools/anvil-memory/CLAUDE.md +49 -0
- package/global/tools/anvil-memory/README.md +42 -0
- package/global/tools/anvil-memory/bun.lock +25 -0
- package/global/tools/anvil-memory/bunfig.toml +9 -0
- package/global/tools/anvil-memory/package.json +23 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
- package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
- package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
- package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
- package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
- package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
- package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
- package/global/tools/anvil-memory/src/commands/get.ts +115 -0
- package/global/tools/anvil-memory/src/commands/init.ts +94 -0
- package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
- package/global/tools/anvil-memory/src/commands/search.ts +112 -0
- package/global/tools/anvil-memory/src/db.ts +638 -0
- package/global/tools/anvil-memory/src/index.ts +205 -0
- package/global/tools/anvil-memory/src/types.ts +122 -0
- package/global/tools/anvil-memory/tsconfig.json +29 -0
- package/global/tools/ralph-loop.sh +359 -0
- package/package.json +45 -0
- package/scripts/anvil +822 -0
- package/scripts/extract_patterns.py +222 -0
- package/scripts/init-project.sh +541 -0
- package/scripts/install.sh +229 -0
- package/scripts/postinstall.js +41 -0
- package/scripts/rollback.sh +188 -0
- package/scripts/sync.sh +623 -0
- package/scripts/test-statusline.sh +248 -0
- package/scripts/update_claude_md.py +224 -0
- package/scripts/verify.sh +255 -0
package/scripts/anvil
ADDED
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Anvil Development Framework CLI
|
|
5
|
+
#
|
|
6
|
+
# Usage: anvil init [options]
|
|
7
|
+
#
|
|
8
|
+
# Scaffolds new projects with Anvil Framework configuration.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
# Version
|
|
14
|
+
VERSION="1.3.0"
|
|
15
|
+
|
|
16
|
+
# Colors
|
|
17
|
+
RED='\033[0;31m'
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[1;33m'
|
|
20
|
+
BLUE='\033[0;34m'
|
|
21
|
+
CYAN='\033[0;36m'
|
|
22
|
+
BOLD='\033[1m'
|
|
23
|
+
NC='\033[0m' # No Color
|
|
24
|
+
|
|
25
|
+
# Determine anvil home directory
|
|
26
|
+
if [ -n "$ANVIL_HOME" ]; then
|
|
27
|
+
ANVIL_DIR="$ANVIL_HOME"
|
|
28
|
+
else
|
|
29
|
+
# Default to where this script lives
|
|
30
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
31
|
+
ANVIL_DIR="$(dirname "$SCRIPT_DIR")"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Default options
|
|
35
|
+
DRY_RUN=false
|
|
36
|
+
FORCE=false
|
|
37
|
+
TEMPLATE="generic"
|
|
38
|
+
WITH_LINEAR=false
|
|
39
|
+
WITH_CODE_REVIEW=false
|
|
40
|
+
NO_HOOKS=false
|
|
41
|
+
NO_TTS=false
|
|
42
|
+
NO_MEMORY=false
|
|
43
|
+
NO_STATUSLINE=false
|
|
44
|
+
TARGET_DIR="$(pwd)"
|
|
45
|
+
|
|
46
|
+
# Show help
|
|
47
|
+
show_help() {
|
|
48
|
+
cat << EOF
|
|
49
|
+
${BOLD}Anvil Development Framework CLI${NC}
|
|
50
|
+
|
|
51
|
+
${BOLD}USAGE${NC}
|
|
52
|
+
anvil init [options]
|
|
53
|
+
anvil --help
|
|
54
|
+
anvil --version
|
|
55
|
+
|
|
56
|
+
${BOLD}COMMANDS${NC}
|
|
57
|
+
init Initialize Anvil in the current directory
|
|
58
|
+
|
|
59
|
+
${BOLD}OPTIONS${NC}
|
|
60
|
+
--template <type> Project template: saas, api-python, generic (default: generic)
|
|
61
|
+
--with-linear Run /linear-setup after initialization
|
|
62
|
+
--with-code-review Enable code review integration in config
|
|
63
|
+
--no-tts Disable TTS voice announcements
|
|
64
|
+
--no-memory Disable claude-mem context loading
|
|
65
|
+
--no-statusline Disable custom statusline display
|
|
66
|
+
--no-hooks Skip ALL hooks (includes safety hooks - use with caution)
|
|
67
|
+
--force Overwrite existing files (backs up first)
|
|
68
|
+
--dry-run Show what would be created without making changes
|
|
69
|
+
--help, -h Show this help message
|
|
70
|
+
--version, -v Show version number
|
|
71
|
+
|
|
72
|
+
${BOLD}HOOK OPTIONS${NC}
|
|
73
|
+
By default, all hooks and statusline are installed including:
|
|
74
|
+
- Safety hooks (rm -rf protection, .env protection)
|
|
75
|
+
- TTS voice announcements
|
|
76
|
+
- Claude-mem context loading
|
|
77
|
+
- Custom statusline (model, context%, branch, issue, phase, cost)
|
|
78
|
+
|
|
79
|
+
Use --no-tts, --no-memory, or --no-statusline to selectively disable
|
|
80
|
+
features while keeping safety hooks active. Only use --no-hooks if you
|
|
81
|
+
want a completely minimal setup without any hook protections.
|
|
82
|
+
|
|
83
|
+
${BOLD}EXAMPLES${NC}
|
|
84
|
+
anvil init # Full init with all features
|
|
85
|
+
anvil init --template saas # SaaS stack (Next.js + Supabase + Vercel)
|
|
86
|
+
anvil init --template api-python # Python API (FastAPI + PostgreSQL)
|
|
87
|
+
anvil init --with-linear # Full setup with Linear integration
|
|
88
|
+
anvil init --with-code-review # Enable code review in config
|
|
89
|
+
anvil init --no-tts # Without voice announcements
|
|
90
|
+
anvil init --no-memory # Without context loading
|
|
91
|
+
anvil init --no-statusline # Without custom statusline
|
|
92
|
+
anvil init --no-tts --no-memory # Safety hooks only
|
|
93
|
+
anvil init --no-hooks # Minimal setup (no safety hooks!)
|
|
94
|
+
anvil init --dry-run # Preview changes
|
|
95
|
+
|
|
96
|
+
${BOLD}ENVIRONMENT${NC}
|
|
97
|
+
ANVIL_HOME Path to Anvil framework installation (auto-detected if not set)
|
|
98
|
+
|
|
99
|
+
EOF
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Show version
|
|
103
|
+
show_version() {
|
|
104
|
+
echo "anvil version $VERSION"
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# Log functions
|
|
108
|
+
log_info() {
|
|
109
|
+
echo -e "${BLUE}$1${NC}"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
log_success() {
|
|
113
|
+
echo -e " ${GREEN}✓${NC} $1"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
log_skip() {
|
|
117
|
+
echo -e " ${YELLOW}⊘${NC} $1"
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
log_warn() {
|
|
121
|
+
echo -e " ${YELLOW}⚠${NC} $1"
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
log_error() {
|
|
125
|
+
echo -e "${RED}Error: $1${NC}" >&2
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
log_dry() {
|
|
129
|
+
echo -e " ${CYAN}[DRY RUN]${NC} Would create: $1"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# Create directory (respects dry-run)
|
|
133
|
+
create_dir() {
|
|
134
|
+
local dir="$1"
|
|
135
|
+
if [ "$DRY_RUN" = true ]; then
|
|
136
|
+
log_dry "$dir/"
|
|
137
|
+
else
|
|
138
|
+
mkdir -p "$dir"
|
|
139
|
+
log_success "$dir/"
|
|
140
|
+
fi
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# Copy file (respects dry-run and force)
|
|
144
|
+
copy_file() {
|
|
145
|
+
local src="$1"
|
|
146
|
+
local dest="$2"
|
|
147
|
+
local display_name="$3"
|
|
148
|
+
|
|
149
|
+
if [ "$DRY_RUN" = true ]; then
|
|
150
|
+
if [ -f "$dest" ] && [ "$FORCE" = false ]; then
|
|
151
|
+
log_dry "$display_name (exists, would skip)"
|
|
152
|
+
else
|
|
153
|
+
log_dry "$display_name"
|
|
154
|
+
fi
|
|
155
|
+
return
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
if [ -f "$dest" ] && [ "$FORCE" = false ]; then
|
|
159
|
+
log_skip "$display_name (exists, use --force to overwrite)"
|
|
160
|
+
return
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
# Backup if force and file exists
|
|
164
|
+
if [ -f "$dest" ] && [ "$FORCE" = true ]; then
|
|
165
|
+
backup_dir="$TARGET_DIR/.claude/.backup"
|
|
166
|
+
mkdir -p "$backup_dir"
|
|
167
|
+
cp "$dest" "$backup_dir/$(basename "$dest").$(date +%Y%m%d%H%M%S)"
|
|
168
|
+
log_info "Backed up existing $display_name"
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
cp "$src" "$dest"
|
|
172
|
+
log_success "$display_name"
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# Create symlink (respects dry-run)
|
|
176
|
+
create_symlink() {
|
|
177
|
+
local src="$1"
|
|
178
|
+
local dest="$2"
|
|
179
|
+
local display_name="$3"
|
|
180
|
+
|
|
181
|
+
if [ "$DRY_RUN" = true ]; then
|
|
182
|
+
log_dry "$display_name → $src"
|
|
183
|
+
return
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Remove existing symlink or file
|
|
187
|
+
if [ -L "$dest" ] || [ -f "$dest" ]; then
|
|
188
|
+
if [ "$FORCE" = true ]; then
|
|
189
|
+
rm -f "$dest"
|
|
190
|
+
else
|
|
191
|
+
log_skip "$display_name (exists)"
|
|
192
|
+
return
|
|
193
|
+
fi
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
ln -s "$src" "$dest"
|
|
197
|
+
log_success "$display_name → $(basename "$src")"
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Check if Anvil is already initialized
|
|
201
|
+
check_existing() {
|
|
202
|
+
if [ -d "$TARGET_DIR/.claude" ]; then
|
|
203
|
+
if [ "$FORCE" = false ]; then
|
|
204
|
+
log_error "Existing Anvil configuration found at $TARGET_DIR/.claude/"
|
|
205
|
+
echo ""
|
|
206
|
+
echo "Use --force to overwrite (existing files will be backed up to .claude/.backup/)"
|
|
207
|
+
echo "Use --dry-run to preview what would change"
|
|
208
|
+
exit 1
|
|
209
|
+
fi
|
|
210
|
+
fi
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
# Generate settings.local.json based on flags
|
|
214
|
+
generate_settings() {
|
|
215
|
+
local settings_file="$TARGET_DIR/.claude/settings.local.json"
|
|
216
|
+
|
|
217
|
+
if [ "$DRY_RUN" = true ]; then
|
|
218
|
+
if [ "$NO_HOOKS" = true ]; then
|
|
219
|
+
log_dry "settings.local.json (minimal - no hooks)"
|
|
220
|
+
elif [ "$NO_TTS" = true ] && [ "$NO_MEMORY" = true ]; then
|
|
221
|
+
log_dry "settings.local.json (safety hooks only)"
|
|
222
|
+
elif [ "$NO_TTS" = true ]; then
|
|
223
|
+
log_dry "settings.local.json (no TTS)"
|
|
224
|
+
elif [ "$NO_MEMORY" = true ]; then
|
|
225
|
+
log_dry "settings.local.json (no memory)"
|
|
226
|
+
else
|
|
227
|
+
log_dry "settings.local.json (full)"
|
|
228
|
+
fi
|
|
229
|
+
return
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
if [ -f "$settings_file" ] && [ "$FORCE" = false ]; then
|
|
233
|
+
log_skip "settings.local.json (exists)"
|
|
234
|
+
return
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
# Build session_start command based on flags
|
|
238
|
+
local session_cmd="uv run .claude/hooks/session_start.py"
|
|
239
|
+
if [ "$NO_MEMORY" = false ]; then
|
|
240
|
+
session_cmd="$session_cmd --load-context"
|
|
241
|
+
fi
|
|
242
|
+
session_cmd="$session_cmd --register-agent"
|
|
243
|
+
if [ "$NO_TTS" = false ]; then
|
|
244
|
+
session_cmd="$session_cmd --announce"
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
# Build pre_tool_use command based on flags
|
|
248
|
+
local pre_cmd="uv run .claude/hooks/pre_tool_use.py"
|
|
249
|
+
if [ "$NO_TTS" = false ]; then
|
|
250
|
+
pre_cmd="$pre_cmd --announce"
|
|
251
|
+
fi
|
|
252
|
+
|
|
253
|
+
# Build post_tool_use command based on flags
|
|
254
|
+
local post_cmd="uv run .claude/hooks/post_tool_use.py"
|
|
255
|
+
if [ "$NO_TTS" = false ]; then
|
|
256
|
+
post_cmd="$post_cmd --announce"
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
# Build subagent_start command
|
|
260
|
+
local subagent_start_cmd="uv run .claude/hooks/subagent_start.py --log --inject-context"
|
|
261
|
+
|
|
262
|
+
# Build subagent_stop command based on flags
|
|
263
|
+
local subagent_stop_cmd="uv run .claude/hooks/subagent_stop.py"
|
|
264
|
+
if [ "$NO_TTS" = false ]; then
|
|
265
|
+
subagent_stop_cmd="$subagent_stop_cmd --announce"
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
# Build permission_request command (always log, safety checks always active)
|
|
269
|
+
local permission_cmd="uv run .claude/hooks/permission_request.py --log"
|
|
270
|
+
|
|
271
|
+
# Build statusLine section (unless disabled)
|
|
272
|
+
local statusline_section=""
|
|
273
|
+
if [ "$NO_STATUSLINE" = false ]; then
|
|
274
|
+
statusline_section=',
|
|
275
|
+
"statusLine": {
|
|
276
|
+
"type": "command",
|
|
277
|
+
"command": "bash .claude/hooks/statusline.sh"
|
|
278
|
+
}'
|
|
279
|
+
fi
|
|
280
|
+
|
|
281
|
+
# Write the settings file
|
|
282
|
+
cat > "$settings_file" << SETTINGS_EOF
|
|
283
|
+
{
|
|
284
|
+
"permissions": {
|
|
285
|
+
"allow": [],
|
|
286
|
+
"deny": []
|
|
287
|
+
},
|
|
288
|
+
"hooks": {
|
|
289
|
+
"SessionStart": [
|
|
290
|
+
{
|
|
291
|
+
"matcher": "",
|
|
292
|
+
"hooks": [
|
|
293
|
+
{
|
|
294
|
+
"type": "command",
|
|
295
|
+
"command": "$session_cmd"
|
|
296
|
+
}
|
|
297
|
+
]
|
|
298
|
+
}
|
|
299
|
+
],
|
|
300
|
+
"PreToolUse": [
|
|
301
|
+
{
|
|
302
|
+
"matcher": "",
|
|
303
|
+
"hooks": [
|
|
304
|
+
{
|
|
305
|
+
"type": "command",
|
|
306
|
+
"command": "$pre_cmd"
|
|
307
|
+
}
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
],
|
|
311
|
+
"PostToolUse": [
|
|
312
|
+
{
|
|
313
|
+
"matcher": "",
|
|
314
|
+
"hooks": [
|
|
315
|
+
{
|
|
316
|
+
"type": "command",
|
|
317
|
+
"command": "$post_cmd"
|
|
318
|
+
}
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"SubagentStart": [
|
|
323
|
+
{
|
|
324
|
+
"matcher": "",
|
|
325
|
+
"hooks": [
|
|
326
|
+
{
|
|
327
|
+
"type": "command",
|
|
328
|
+
"command": "$subagent_start_cmd"
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
],
|
|
333
|
+
"SubagentStop": [
|
|
334
|
+
{
|
|
335
|
+
"matcher": "",
|
|
336
|
+
"hooks": [
|
|
337
|
+
{
|
|
338
|
+
"type": "command",
|
|
339
|
+
"command": "$subagent_stop_cmd"
|
|
340
|
+
}
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
],
|
|
344
|
+
"PermissionRequest": [
|
|
345
|
+
{
|
|
346
|
+
"matcher": "",
|
|
347
|
+
"hooks": [
|
|
348
|
+
{
|
|
349
|
+
"type": "command",
|
|
350
|
+
"command": "$permission_cmd"
|
|
351
|
+
}
|
|
352
|
+
]
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
}$statusline_section
|
|
356
|
+
}
|
|
357
|
+
SETTINGS_EOF
|
|
358
|
+
|
|
359
|
+
# Determine what mode was used
|
|
360
|
+
if [ "$NO_TTS" = true ] && [ "$NO_MEMORY" = true ]; then
|
|
361
|
+
log_success "settings.local.json (safety hooks only)"
|
|
362
|
+
elif [ "$NO_TTS" = true ]; then
|
|
363
|
+
log_success "settings.local.json (no TTS)"
|
|
364
|
+
elif [ "$NO_MEMORY" = true ]; then
|
|
365
|
+
log_success "settings.local.json (no memory)"
|
|
366
|
+
else
|
|
367
|
+
log_success "settings.local.json (full)"
|
|
368
|
+
fi
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
# Generate minimal settings (no hooks at all)
|
|
372
|
+
generate_minimal_settings() {
|
|
373
|
+
local settings_file="$TARGET_DIR/.claude/settings.local.json"
|
|
374
|
+
|
|
375
|
+
if [ "$DRY_RUN" = true ]; then
|
|
376
|
+
log_dry "settings.local.json (minimal - no hooks)"
|
|
377
|
+
return
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
if [ -f "$settings_file" ] && [ "$FORCE" = false ]; then
|
|
381
|
+
log_skip "settings.local.json (exists)"
|
|
382
|
+
return
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
cat > "$settings_file" << 'SETTINGS_EOF'
|
|
386
|
+
{
|
|
387
|
+
"permissions": {
|
|
388
|
+
"allow": [],
|
|
389
|
+
"deny": []
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
SETTINGS_EOF
|
|
393
|
+
log_success "settings.local.json (minimal)"
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
# Generate anvil.config.json for framework settings
|
|
397
|
+
generate_anvil_config() {
|
|
398
|
+
local config_file="$TARGET_DIR/.claude/anvil.config.json"
|
|
399
|
+
|
|
400
|
+
if [ "$DRY_RUN" = true ]; then
|
|
401
|
+
if [ "$WITH_CODE_REVIEW" = true ]; then
|
|
402
|
+
log_dry "anvil.config.json (with code review)"
|
|
403
|
+
else
|
|
404
|
+
log_dry "anvil.config.json (framework settings)"
|
|
405
|
+
fi
|
|
406
|
+
return
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
if [ -f "$config_file" ] && [ "$FORCE" = false ]; then
|
|
410
|
+
log_skip "anvil.config.json (exists)"
|
|
411
|
+
return
|
|
412
|
+
fi
|
|
413
|
+
|
|
414
|
+
if [ "$WITH_CODE_REVIEW" = true ]; then
|
|
415
|
+
cat > "$config_file" << 'CONFIG_EOF'
|
|
416
|
+
{
|
|
417
|
+
"version": "1.1",
|
|
418
|
+
"autoRetro": false,
|
|
419
|
+
"autoHealthcheck": false,
|
|
420
|
+
"codeReview": {
|
|
421
|
+
"enabled": true,
|
|
422
|
+
"tool": "coderabbit",
|
|
423
|
+
"command": "coderabbit --prompt-only",
|
|
424
|
+
"enforcement": "soft"
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
CONFIG_EOF
|
|
428
|
+
log_success "anvil.config.json (with code review)"
|
|
429
|
+
else
|
|
430
|
+
cat > "$config_file" << 'CONFIG_EOF'
|
|
431
|
+
{
|
|
432
|
+
"version": "1.1",
|
|
433
|
+
"autoRetro": false,
|
|
434
|
+
"autoHealthcheck": false,
|
|
435
|
+
"codeReview": {
|
|
436
|
+
"enabled": false,
|
|
437
|
+
"tool": "coderabbit",
|
|
438
|
+
"command": "coderabbit --prompt-only",
|
|
439
|
+
"enforcement": "soft"
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
CONFIG_EOF
|
|
443
|
+
log_success "anvil.config.json"
|
|
444
|
+
fi
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
# Update .gitignore with Anvil-specific exclusions
|
|
448
|
+
update_gitignore() {
|
|
449
|
+
local gitignore_file="$TARGET_DIR/.gitignore"
|
|
450
|
+
local anvil_marker="# Anvil Framework"
|
|
451
|
+
local anvil_state_entry=".claude/anvil-state.json"
|
|
452
|
+
|
|
453
|
+
if [ "$DRY_RUN" = true ]; then
|
|
454
|
+
if [ -f "$gitignore_file" ]; then
|
|
455
|
+
log_dry ".gitignore (add anvil-state.json)"
|
|
456
|
+
else
|
|
457
|
+
log_dry ".gitignore (create with anvil-state.json)"
|
|
458
|
+
fi
|
|
459
|
+
return
|
|
460
|
+
fi
|
|
461
|
+
|
|
462
|
+
# Check if entry already exists
|
|
463
|
+
if [ -f "$gitignore_file" ] && grep -q "$anvil_state_entry" "$gitignore_file" 2>/dev/null; then
|
|
464
|
+
log_skip ".gitignore (anvil-state.json already present)"
|
|
465
|
+
return
|
|
466
|
+
fi
|
|
467
|
+
|
|
468
|
+
# Add the Anvil section to .gitignore
|
|
469
|
+
if [ -f "$gitignore_file" ]; then
|
|
470
|
+
# Append to existing file
|
|
471
|
+
echo "" >> "$gitignore_file"
|
|
472
|
+
echo "$anvil_marker" >> "$gitignore_file"
|
|
473
|
+
echo "$anvil_state_entry" >> "$gitignore_file"
|
|
474
|
+
log_success ".gitignore (added anvil-state.json)"
|
|
475
|
+
else
|
|
476
|
+
# Create new file
|
|
477
|
+
cat > "$gitignore_file" << GITIGNORE_EOF
|
|
478
|
+
$anvil_marker
|
|
479
|
+
$anvil_state_entry
|
|
480
|
+
GITIGNORE_EOF
|
|
481
|
+
log_success ".gitignore (created with anvil-state.json)"
|
|
482
|
+
fi
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
# Main init function
|
|
486
|
+
do_init() {
|
|
487
|
+
echo ""
|
|
488
|
+
echo -e "${BOLD}${BLUE}Anvil Development Framework${NC} ${CYAN}v${VERSION}${NC}"
|
|
489
|
+
echo "══════════════════════════════════════"
|
|
490
|
+
echo ""
|
|
491
|
+
|
|
492
|
+
if [ "$DRY_RUN" = true ]; then
|
|
493
|
+
echo -e "${CYAN}[DRY RUN MODE] No changes will be made${NC}"
|
|
494
|
+
echo ""
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
# Validate Anvil installation
|
|
498
|
+
if [ ! -d "$ANVIL_DIR/project" ]; then
|
|
499
|
+
log_error "Anvil framework not found at $ANVIL_DIR"
|
|
500
|
+
echo "Set ANVIL_HOME environment variable to your Anvil installation path"
|
|
501
|
+
exit 1
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
# Show configuration
|
|
505
|
+
log_info "Template: $TEMPLATE"
|
|
506
|
+
log_info "Target: $TARGET_DIR"
|
|
507
|
+
|
|
508
|
+
# Show hooks status
|
|
509
|
+
if [ "$NO_HOOKS" = true ]; then
|
|
510
|
+
echo -e "${YELLOW}Hooks: DISABLED (no safety protections!)${NC}"
|
|
511
|
+
else
|
|
512
|
+
local hooks_status="enabled"
|
|
513
|
+
local hooks_details=""
|
|
514
|
+
if [ "$NO_TTS" = true ]; then
|
|
515
|
+
hooks_details="${hooks_details}, no TTS"
|
|
516
|
+
fi
|
|
517
|
+
if [ "$NO_MEMORY" = true ]; then
|
|
518
|
+
hooks_details="${hooks_details}, no memory"
|
|
519
|
+
fi
|
|
520
|
+
if [ -n "$hooks_details" ]; then
|
|
521
|
+
hooks_status="enabled (${hooks_details:2})" # Remove leading ", "
|
|
522
|
+
fi
|
|
523
|
+
log_info "Hooks: $hooks_status"
|
|
524
|
+
fi
|
|
525
|
+
echo ""
|
|
526
|
+
|
|
527
|
+
# Safety warning for --no-hooks
|
|
528
|
+
if [ "$NO_HOOKS" = true ]; then
|
|
529
|
+
echo -e "${YELLOW}════════════════════════════════════════${NC}"
|
|
530
|
+
echo -e "${YELLOW} ⚠️ WARNING: Safety hooks disabled!${NC}"
|
|
531
|
+
echo -e "${YELLOW}════════════════════════════════════════${NC}"
|
|
532
|
+
echo ""
|
|
533
|
+
echo "Without hooks, you lose these protections:"
|
|
534
|
+
echo " • rm -rf command blocking"
|
|
535
|
+
echo " • .env file access prevention"
|
|
536
|
+
echo " • TTS voice announcements"
|
|
537
|
+
echo " • Claude-mem context loading"
|
|
538
|
+
echo ""
|
|
539
|
+
echo "Consider using --no-tts or --no-memory instead"
|
|
540
|
+
echo "to keep safety protections while disabling features."
|
|
541
|
+
echo ""
|
|
542
|
+
fi
|
|
543
|
+
|
|
544
|
+
# Check for existing installation (unless force)
|
|
545
|
+
check_existing
|
|
546
|
+
|
|
547
|
+
# Create directory structure
|
|
548
|
+
log_info "Creating directory structure..."
|
|
549
|
+
create_dir "$TARGET_DIR/.claude"
|
|
550
|
+
create_dir "$TARGET_DIR/.claude/specs/current"
|
|
551
|
+
create_dir "$TARGET_DIR/.claude/specs/archive"
|
|
552
|
+
create_dir "$TARGET_DIR/.claude/changes"
|
|
553
|
+
create_dir "$TARGET_DIR/.claude/handoffs"
|
|
554
|
+
create_dir "$TARGET_DIR/.claude/docs"
|
|
555
|
+
create_dir "$TARGET_DIR/.claude/examples"
|
|
556
|
+
create_dir "$TARGET_DIR/.claude/commands"
|
|
557
|
+
create_dir "$TARGET_DIR/.claude/agents"
|
|
558
|
+
create_dir "$TARGET_DIR/.claude/retros"
|
|
559
|
+
create_dir "$TARGET_DIR/.claude/rules"
|
|
560
|
+
|
|
561
|
+
# Create hooks directory only if hooks enabled
|
|
562
|
+
if [ "$NO_HOOKS" = false ]; then
|
|
563
|
+
create_dir "$TARGET_DIR/.claude/hooks"
|
|
564
|
+
create_dir "$TARGET_DIR/.claude/hooks/utils"
|
|
565
|
+
create_dir "$TARGET_DIR/.claude/hooks/utils/tts"
|
|
566
|
+
fi
|
|
567
|
+
|
|
568
|
+
echo ""
|
|
569
|
+
|
|
570
|
+
# Copy templates
|
|
571
|
+
log_info "Installing templates..."
|
|
572
|
+
|
|
573
|
+
# CLAUDE.md - use template-specific version if available
|
|
574
|
+
TEMPLATE_DIR="$ANVIL_DIR/project/templates/$TEMPLATE"
|
|
575
|
+
if [ -f "$TEMPLATE_DIR/CLAUDE.md" ]; then
|
|
576
|
+
copy_file "$TEMPLATE_DIR/CLAUDE.md" "$TARGET_DIR/.claude/CLAUDE.md" "CLAUDE.md ($TEMPLATE template)"
|
|
577
|
+
elif [ -f "$ANVIL_DIR/project/CLAUDE.md.template" ]; then
|
|
578
|
+
copy_file "$ANVIL_DIR/project/CLAUDE.md.template" "$TARGET_DIR/.claude/CLAUDE.md" "CLAUDE.md (generic)"
|
|
579
|
+
fi
|
|
580
|
+
|
|
581
|
+
# Shared templates
|
|
582
|
+
if [ -f "$ANVIL_DIR/project/constitution.md.template" ]; then
|
|
583
|
+
copy_file "$ANVIL_DIR/project/constitution.md.template" "$TARGET_DIR/.claude/constitution.md" "constitution.md"
|
|
584
|
+
fi
|
|
585
|
+
|
|
586
|
+
if [ -f "$ANVIL_DIR/project/product.md.template" ]; then
|
|
587
|
+
copy_file "$ANVIL_DIR/project/product.md.template" "$TARGET_DIR/.claude/product.md" "product.md"
|
|
588
|
+
fi
|
|
589
|
+
|
|
590
|
+
if [ -f "$ANVIL_DIR/project/coordination.md.template" ]; then
|
|
591
|
+
copy_file "$ANVIL_DIR/project/coordination.md.template" "$TARGET_DIR/.claude/coordination.md" "coordination.md"
|
|
592
|
+
fi
|
|
593
|
+
|
|
594
|
+
# Copy rules templates
|
|
595
|
+
if [ -d "$ANVIL_DIR/project/rules" ]; then
|
|
596
|
+
for rules_file in "$ANVIL_DIR/project/rules"/*.md; do
|
|
597
|
+
if [ -f "$rules_file" ]; then
|
|
598
|
+
BASENAME=$(basename "$rules_file")
|
|
599
|
+
copy_file "$rules_file" "$TARGET_DIR/.claude/rules/$BASENAME" "rules/$BASENAME"
|
|
600
|
+
fi
|
|
601
|
+
done
|
|
602
|
+
fi
|
|
603
|
+
|
|
604
|
+
echo ""
|
|
605
|
+
|
|
606
|
+
# Install hooks via symlinks (unless --no-hooks)
|
|
607
|
+
if [ "$NO_HOOKS" = false ]; then
|
|
608
|
+
log_info "Installing hooks (symlinks)..."
|
|
609
|
+
|
|
610
|
+
# Symlink hook files
|
|
611
|
+
if [ -d "$ANVIL_DIR/project/hooks" ]; then
|
|
612
|
+
for hook_file in "$ANVIL_DIR/project/hooks"/*.py; do
|
|
613
|
+
if [ -f "$hook_file" ]; then
|
|
614
|
+
BASENAME=$(basename "$hook_file")
|
|
615
|
+
create_symlink "$hook_file" "$TARGET_DIR/.claude/hooks/$BASENAME" "hooks/$BASENAME"
|
|
616
|
+
fi
|
|
617
|
+
done
|
|
618
|
+
|
|
619
|
+
# Symlink TTS utilities (even if --no-tts, in case user changes mind later)
|
|
620
|
+
if [ -d "$ANVIL_DIR/project/hooks/utils/tts" ]; then
|
|
621
|
+
for tts_file in "$ANVIL_DIR/project/hooks/utils/tts"/*.py; do
|
|
622
|
+
if [ -f "$tts_file" ]; then
|
|
623
|
+
BASENAME=$(basename "$tts_file")
|
|
624
|
+
create_symlink "$tts_file" "$TARGET_DIR/.claude/hooks/utils/tts/$BASENAME" "hooks/utils/tts/$BASENAME"
|
|
625
|
+
fi
|
|
626
|
+
done
|
|
627
|
+
fi
|
|
628
|
+
fi
|
|
629
|
+
|
|
630
|
+
echo ""
|
|
631
|
+
|
|
632
|
+
# Install test harnesses (symlinks)
|
|
633
|
+
log_info "Installing test harnesses (symlinks)..."
|
|
634
|
+
create_dir "$TARGET_DIR/.claude/tests"
|
|
635
|
+
if [ -d "$ANVIL_DIR/project/tests" ]; then
|
|
636
|
+
for test_file in "$ANVIL_DIR/project/tests"/*.sh; do
|
|
637
|
+
if [ -f "$test_file" ]; then
|
|
638
|
+
BASENAME=$(basename "$test_file")
|
|
639
|
+
create_symlink "$test_file" "$TARGET_DIR/.claude/tests/$BASENAME" "tests/$BASENAME"
|
|
640
|
+
fi
|
|
641
|
+
done
|
|
642
|
+
# Also symlink the README
|
|
643
|
+
if [ -f "$ANVIL_DIR/project/tests/README.md" ]; then
|
|
644
|
+
create_symlink "$ANVIL_DIR/project/tests/README.md" "$TARGET_DIR/.claude/tests/README.md" "tests/README.md"
|
|
645
|
+
fi
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
echo ""
|
|
649
|
+
|
|
650
|
+
# Create settings.local.json with hook configurations
|
|
651
|
+
log_info "Creating settings.local.json..."
|
|
652
|
+
generate_settings
|
|
653
|
+
else
|
|
654
|
+
# Minimal settings without hooks
|
|
655
|
+
log_info "Creating minimal settings.local.json (no hooks)..."
|
|
656
|
+
generate_minimal_settings
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
# Create anvil.config.json for framework settings
|
|
660
|
+
log_info "Creating anvil.config.json..."
|
|
661
|
+
generate_anvil_config
|
|
662
|
+
|
|
663
|
+
# Update .gitignore with Anvil exclusions
|
|
664
|
+
log_info "Updating .gitignore..."
|
|
665
|
+
update_gitignore
|
|
666
|
+
|
|
667
|
+
echo ""
|
|
668
|
+
|
|
669
|
+
# Install commands via symlinks (from global/commands/)
|
|
670
|
+
log_info "Installing commands (symlinks)..."
|
|
671
|
+
if [ -d "$ANVIL_DIR/global/commands" ]; then
|
|
672
|
+
for cmd_file in "$ANVIL_DIR/global/commands"/*.md; do
|
|
673
|
+
if [ -f "$cmd_file" ]; then
|
|
674
|
+
BASENAME=$(basename "$cmd_file")
|
|
675
|
+
create_symlink "$cmd_file" "$TARGET_DIR/.claude/commands/$BASENAME" "commands/$BASENAME"
|
|
676
|
+
fi
|
|
677
|
+
done
|
|
678
|
+
fi
|
|
679
|
+
|
|
680
|
+
echo ""
|
|
681
|
+
|
|
682
|
+
# Summary
|
|
683
|
+
if [ "$DRY_RUN" = true ]; then
|
|
684
|
+
echo ""
|
|
685
|
+
echo -e "${CYAN}[DRY RUN] No changes made${NC}"
|
|
686
|
+
echo "Run without --dry-run to apply these changes"
|
|
687
|
+
else
|
|
688
|
+
echo ""
|
|
689
|
+
echo -e "${GREEN}════════════════════════════════════════${NC}"
|
|
690
|
+
echo -e "${GREEN} Anvil initialized successfully!${NC}"
|
|
691
|
+
echo -e "${GREEN}════════════════════════════════════════${NC}"
|
|
692
|
+
echo ""
|
|
693
|
+
echo "Project configured at: $TARGET_DIR/.claude/"
|
|
694
|
+
echo ""
|
|
695
|
+
echo -e "${BOLD}Next steps:${NC}"
|
|
696
|
+
echo " 1. Edit .claude/CLAUDE.md with your project details"
|
|
697
|
+
echo " 2. Review .claude/constitution.md principles"
|
|
698
|
+
echo " 3. Fill out .claude/product.md"
|
|
699
|
+
if [ "$NO_HOOKS" = false ]; then
|
|
700
|
+
if [ "$NO_TTS" = true ] && [ "$NO_MEMORY" = true ]; then
|
|
701
|
+
echo " 4. Safety hooks active (TTS and memory disabled)"
|
|
702
|
+
elif [ "$NO_TTS" = true ]; then
|
|
703
|
+
echo " 4. Hooks ready (TTS disabled, memory enabled)"
|
|
704
|
+
elif [ "$NO_MEMORY" = true ]; then
|
|
705
|
+
echo " 4. Hooks ready (TTS enabled, memory disabled)"
|
|
706
|
+
else
|
|
707
|
+
echo " 4. Hooks ready - TTS and memory enabled"
|
|
708
|
+
fi
|
|
709
|
+
else
|
|
710
|
+
echo -e " 4. ${YELLOW}No hooks installed - consider adding safety hooks${NC}"
|
|
711
|
+
fi
|
|
712
|
+
echo ""
|
|
713
|
+
echo "To start using Anvil, open Claude Code and run /orient"
|
|
714
|
+
|
|
715
|
+
# Linear setup if requested
|
|
716
|
+
if [ "$WITH_LINEAR" = true ]; then
|
|
717
|
+
echo ""
|
|
718
|
+
log_info "Linear integration requested..."
|
|
719
|
+
if [ -f "$ANVIL_DIR/project/linear.yaml.template" ]; then
|
|
720
|
+
copy_file "$ANVIL_DIR/project/linear.yaml.template" "$TARGET_DIR/.claude/linear.yaml" "linear.yaml"
|
|
721
|
+
fi
|
|
722
|
+
echo ""
|
|
723
|
+
echo -e "${YELLOW}Run /linear-setup in Claude Code to configure your Linear team${NC}"
|
|
724
|
+
fi
|
|
725
|
+
fi
|
|
726
|
+
|
|
727
|
+
echo ""
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
# Parse arguments
|
|
731
|
+
parse_args() {
|
|
732
|
+
while [[ $# -gt 0 ]]; do
|
|
733
|
+
case $1 in
|
|
734
|
+
init)
|
|
735
|
+
COMMAND="init"
|
|
736
|
+
shift
|
|
737
|
+
;;
|
|
738
|
+
--template)
|
|
739
|
+
if [[ -z "$2" || "$2" == -* ]]; then
|
|
740
|
+
log_error "Option --template requires an argument"
|
|
741
|
+
echo "Valid templates: saas, api-python, generic"
|
|
742
|
+
echo "Usage: anvil init --template <template>"
|
|
743
|
+
exit 1
|
|
744
|
+
fi
|
|
745
|
+
TEMPLATE="$2"
|
|
746
|
+
if [[ ! "$TEMPLATE" =~ ^(saas|api-python|generic)$ ]]; then
|
|
747
|
+
log_error "Invalid template: $TEMPLATE"
|
|
748
|
+
echo "Valid templates: saas, api-python, generic"
|
|
749
|
+
exit 1
|
|
750
|
+
fi
|
|
751
|
+
shift 2
|
|
752
|
+
;;
|
|
753
|
+
--with-linear)
|
|
754
|
+
WITH_LINEAR=true
|
|
755
|
+
shift
|
|
756
|
+
;;
|
|
757
|
+
--with-code-review)
|
|
758
|
+
WITH_CODE_REVIEW=true
|
|
759
|
+
shift
|
|
760
|
+
;;
|
|
761
|
+
--no-hooks)
|
|
762
|
+
NO_HOOKS=true
|
|
763
|
+
shift
|
|
764
|
+
;;
|
|
765
|
+
--no-tts)
|
|
766
|
+
NO_TTS=true
|
|
767
|
+
shift
|
|
768
|
+
;;
|
|
769
|
+
--no-memory)
|
|
770
|
+
NO_MEMORY=true
|
|
771
|
+
shift
|
|
772
|
+
;;
|
|
773
|
+
--no-statusline)
|
|
774
|
+
NO_STATUSLINE=true
|
|
775
|
+
shift
|
|
776
|
+
;;
|
|
777
|
+
--force)
|
|
778
|
+
FORCE=true
|
|
779
|
+
shift
|
|
780
|
+
;;
|
|
781
|
+
--dry-run)
|
|
782
|
+
DRY_RUN=true
|
|
783
|
+
shift
|
|
784
|
+
;;
|
|
785
|
+
--help|-h)
|
|
786
|
+
show_help
|
|
787
|
+
exit 0
|
|
788
|
+
;;
|
|
789
|
+
--version|-v)
|
|
790
|
+
show_version
|
|
791
|
+
exit 0
|
|
792
|
+
;;
|
|
793
|
+
*)
|
|
794
|
+
log_error "Unknown option: $1"
|
|
795
|
+
echo "Run 'anvil --help' for usage"
|
|
796
|
+
exit 1
|
|
797
|
+
;;
|
|
798
|
+
esac
|
|
799
|
+
done
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
# Main
|
|
803
|
+
main() {
|
|
804
|
+
if [ $# -eq 0 ]; then
|
|
805
|
+
show_help
|
|
806
|
+
exit 0
|
|
807
|
+
fi
|
|
808
|
+
|
|
809
|
+
parse_args "$@"
|
|
810
|
+
|
|
811
|
+
case $COMMAND in
|
|
812
|
+
init)
|
|
813
|
+
do_init
|
|
814
|
+
;;
|
|
815
|
+
*)
|
|
816
|
+
show_help
|
|
817
|
+
exit 0
|
|
818
|
+
;;
|
|
819
|
+
esac
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
main "$@"
|