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.
Files changed (190) hide show
  1. package/README.md +719 -0
  2. package/VERSION +1 -0
  3. package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
  4. package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
  5. package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
  6. package/docs/INSTALLATION.md +984 -0
  7. package/docs/anvil-hud.md +469 -0
  8. package/docs/anvil-init.md +255 -0
  9. package/docs/anvil-state.md +210 -0
  10. package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
  11. package/docs/command-reference.md +2022 -0
  12. package/docs/hooks-tts.md +368 -0
  13. package/docs/implementation-guide.md +810 -0
  14. package/docs/linear-github-integration.md +247 -0
  15. package/docs/local-issues.md +677 -0
  16. package/docs/patterns/README.md +419 -0
  17. package/docs/planning-responsibilities.md +139 -0
  18. package/docs/session-workflow.md +573 -0
  19. package/docs/simplification-plan-template.md +297 -0
  20. package/docs/simplification-principles.md +129 -0
  21. package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
  22. package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
  23. package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
  24. package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
  25. package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
  26. package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
  27. package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
  28. package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
  29. package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
  30. package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
  31. package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
  32. package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
  33. package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
  34. package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
  35. package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
  36. package/docs/sync.md +122 -0
  37. package/global/CLAUDE.md +140 -0
  38. package/global/agents/verify-app.md +164 -0
  39. package/global/commands/anvil-settings.md +527 -0
  40. package/global/commands/anvil-sync.md +121 -0
  41. package/global/commands/change.md +197 -0
  42. package/global/commands/clarify.md +252 -0
  43. package/global/commands/cleanup.md +292 -0
  44. package/global/commands/commit-push-pr.md +207 -0
  45. package/global/commands/decay-review.md +127 -0
  46. package/global/commands/discover.md +158 -0
  47. package/global/commands/doc-coverage.md +122 -0
  48. package/global/commands/evidence.md +307 -0
  49. package/global/commands/explore.md +121 -0
  50. package/global/commands/force-exit.md +135 -0
  51. package/global/commands/handoff.md +191 -0
  52. package/global/commands/healthcheck.md +302 -0
  53. package/global/commands/hud.md +84 -0
  54. package/global/commands/insights.md +319 -0
  55. package/global/commands/linear-setup.md +184 -0
  56. package/global/commands/lint-fix.md +198 -0
  57. package/global/commands/orient.md +510 -0
  58. package/global/commands/plan.md +228 -0
  59. package/global/commands/ralph.md +346 -0
  60. package/global/commands/ready.md +182 -0
  61. package/global/commands/release.md +305 -0
  62. package/global/commands/retro.md +96 -0
  63. package/global/commands/shard.md +166 -0
  64. package/global/commands/spec.md +227 -0
  65. package/global/commands/sprint.md +184 -0
  66. package/global/commands/tasks.md +228 -0
  67. package/global/commands/test-and-commit.md +151 -0
  68. package/global/commands/validate.md +132 -0
  69. package/global/commands/verify.md +251 -0
  70. package/global/commands/weekly-review.md +156 -0
  71. package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
  72. package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
  73. package/global/hooks/anvil_memory_observe.ts +322 -0
  74. package/global/hooks/anvil_memory_session.ts +166 -0
  75. package/global/hooks/anvil_memory_stop.ts +187 -0
  76. package/global/hooks/parse_transcript.py +116 -0
  77. package/global/hooks/post_merge_cleanup.sh +132 -0
  78. package/global/hooks/post_tool_format.sh +215 -0
  79. package/global/hooks/ralph_context_monitor.py +240 -0
  80. package/global/hooks/ralph_stop.sh +502 -0
  81. package/global/hooks/statusline.sh +1110 -0
  82. package/global/hooks/statusline_agent_sync.py +224 -0
  83. package/global/hooks/stop_gate.sh +250 -0
  84. package/global/lib/.claude/anvil-state.json +21 -0
  85. package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
  86. package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
  87. package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
  88. package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
  89. package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
  90. package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
  91. package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
  92. package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
  93. package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
  94. package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
  95. package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
  96. package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
  97. package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
  98. package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
  99. package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
  100. package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
  101. package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
  102. package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
  103. package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
  104. package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
  105. package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
  106. package/global/lib/agent_registry.py +995 -0
  107. package/global/lib/anvil-state.sh +435 -0
  108. package/global/lib/claim_service.py +515 -0
  109. package/global/lib/coderabbit_service.py +314 -0
  110. package/global/lib/config_service.py +423 -0
  111. package/global/lib/coordination_service.py +331 -0
  112. package/global/lib/doc_coverage_service.py +1305 -0
  113. package/global/lib/gate_logger.py +316 -0
  114. package/global/lib/github_service.py +310 -0
  115. package/global/lib/handoff_generator.py +775 -0
  116. package/global/lib/hygiene_service.py +712 -0
  117. package/global/lib/issue_models.py +257 -0
  118. package/global/lib/issue_provider.py +339 -0
  119. package/global/lib/linear_data_service.py +210 -0
  120. package/global/lib/linear_provider.py +987 -0
  121. package/global/lib/linear_provider.py.backup +671 -0
  122. package/global/lib/local_provider.py +486 -0
  123. package/global/lib/orient_fast.py +457 -0
  124. package/global/lib/quality_service.py +470 -0
  125. package/global/lib/ralph_prompt_generator.py +563 -0
  126. package/global/lib/ralph_state.py +1202 -0
  127. package/global/lib/state_manager.py +417 -0
  128. package/global/lib/transcript_parser.py +597 -0
  129. package/global/lib/verification_runner.py +557 -0
  130. package/global/lib/verify_iteration.py +490 -0
  131. package/global/lib/verify_subagent.py +250 -0
  132. package/global/skills/README.md +155 -0
  133. package/global/skills/quality-gates/SKILL.md +252 -0
  134. package/global/skills/skill-template/SKILL.md +109 -0
  135. package/global/skills/testing-strategies/SKILL.md +337 -0
  136. package/global/templates/CHANGE-template.md +105 -0
  137. package/global/templates/HANDOFF-template.md +63 -0
  138. package/global/templates/PLAN-template.md +111 -0
  139. package/global/templates/SPEC-template.md +93 -0
  140. package/global/templates/ralph/PROMPT.md.template +89 -0
  141. package/global/templates/ralph/fix_plan.md.template +31 -0
  142. package/global/templates/ralph/progress.txt.template +23 -0
  143. package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
  144. package/global/tests/test_doc_coverage.py +520 -0
  145. package/global/tests/test_issue_models.py +299 -0
  146. package/global/tests/test_local_provider.py +323 -0
  147. package/global/tools/README.md +178 -0
  148. package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
  149. package/global/tools/anvil-hud.py +3622 -0
  150. package/global/tools/anvil-hud.py.bak +3318 -0
  151. package/global/tools/anvil-issue.py +432 -0
  152. package/global/tools/anvil-memory/CLAUDE.md +49 -0
  153. package/global/tools/anvil-memory/README.md +42 -0
  154. package/global/tools/anvil-memory/bun.lock +25 -0
  155. package/global/tools/anvil-memory/bunfig.toml +9 -0
  156. package/global/tools/anvil-memory/package.json +23 -0
  157. package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
  158. package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
  159. package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
  160. package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
  161. package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
  162. package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
  163. package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
  164. package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
  165. package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
  166. package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
  167. package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
  168. package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
  169. package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
  170. package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
  171. package/global/tools/anvil-memory/src/commands/get.ts +115 -0
  172. package/global/tools/anvil-memory/src/commands/init.ts +94 -0
  173. package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
  174. package/global/tools/anvil-memory/src/commands/search.ts +112 -0
  175. package/global/tools/anvil-memory/src/db.ts +638 -0
  176. package/global/tools/anvil-memory/src/index.ts +205 -0
  177. package/global/tools/anvil-memory/src/types.ts +122 -0
  178. package/global/tools/anvil-memory/tsconfig.json +29 -0
  179. package/global/tools/ralph-loop.sh +359 -0
  180. package/package.json +45 -0
  181. package/scripts/anvil +822 -0
  182. package/scripts/extract_patterns.py +222 -0
  183. package/scripts/init-project.sh +541 -0
  184. package/scripts/install.sh +229 -0
  185. package/scripts/postinstall.js +41 -0
  186. package/scripts/rollback.sh +188 -0
  187. package/scripts/sync.sh +623 -0
  188. package/scripts/test-statusline.sh +248 -0
  189. package/scripts/update_claude_md.py +224 -0
  190. package/scripts/verify.sh +255 -0
@@ -0,0 +1,623 @@
1
+ #!/bin/bash
2
+
3
+ #
4
+ # Anvil Development Framework - Sync Script
5
+ #
6
+ # Syncs Anvil framework updates to global config and/or projects
7
+ #
8
+ # Usage:
9
+ # anvil sync --global # Sync to ~/.claude/
10
+ # anvil sync --project /path/to/project # Sync to a specific project
11
+ # anvil sync --project . # Sync to current directory
12
+ # anvil sync --all # Sync global + all registered projects
13
+ # anvil sync --dry-run --project . # Preview changes without applying
14
+ #
15
+
16
+ set -e
17
+
18
+ # Colors
19
+ RED='\033[0;31m'
20
+ GREEN='\033[0;32m'
21
+ YELLOW='\033[1;33m'
22
+ BLUE='\033[0;34m'
23
+ CYAN='\033[0;36m'
24
+ DIM='\033[2m'
25
+ NC='\033[0m' # No Color
26
+
27
+ # Symbols
28
+ CHECK="${GREEN}✓${NC}"
29
+ CROSS="${RED}✗${NC}"
30
+ ARROW="${BLUE}→${NC}"
31
+ SKIP="${YELLOW}⊘${NC}"
32
+
33
+ # Configuration
34
+ ANVIL_DIR=""
35
+ DRY_RUN=false
36
+ FORCE=false
37
+ VERBOSE=false
38
+ SYNC_GLOBAL=false
39
+ SYNC_PROJECT=""
40
+ SYNC_ALL=false
41
+
42
+ # Files that should NEVER be overwritten (user customizations)
43
+ PROTECTED_FILES=(
44
+ "CLAUDE.md"
45
+ "product.md"
46
+ "constitution.md"
47
+ "settings.local.json"
48
+ "coordination.md"
49
+ "linear.yaml"
50
+ )
51
+
52
+ # Files that should ALWAYS be synced (framework updates)
53
+ SYNC_ALWAYS=(
54
+ "hooks/"
55
+ "examples/"
56
+ )
57
+
58
+
59
+ #######################################
60
+ # Helper Functions
61
+ #######################################
62
+
63
+ print_banner() {
64
+ echo ""
65
+ echo -e "${BLUE}╔═══════════════════════════════════════╗${NC}"
66
+ echo -e "${BLUE}║${NC} Anvil Framework Sync Tool ${BLUE}║${NC}"
67
+ echo -e "${BLUE}╚═══════════════════════════════════════╝${NC}"
68
+ echo ""
69
+ }
70
+
71
+ log_info() {
72
+ echo -e "${BLUE}[INFO]${NC} $1"
73
+ }
74
+
75
+ log_success() {
76
+ echo -e "${GREEN}[SUCCESS]${NC} $1"
77
+ }
78
+
79
+ log_warning() {
80
+ echo -e "${YELLOW}[WARNING]${NC} $1"
81
+ }
82
+
83
+ log_error() {
84
+ echo -e "${RED}[ERROR]${NC} $1"
85
+ }
86
+
87
+ log_verbose() {
88
+ if [ "$VERBOSE" = true ]; then
89
+ echo -e "${DIM}[DEBUG] $1${NC}"
90
+ fi
91
+ }
92
+
93
+ log_dry_run() {
94
+ if [ "$DRY_RUN" = true ]; then
95
+ echo -e "${CYAN}[DRY-RUN]${NC} $1"
96
+ fi
97
+ }
98
+
99
+ # Check if file is protected
100
+ is_protected() {
101
+ local filename=$(basename "$1")
102
+ for protected in "${PROTECTED_FILES[@]}"; do
103
+ if [ "$filename" = "$protected" ]; then
104
+ return 0
105
+ fi
106
+ done
107
+ return 1
108
+ }
109
+
110
+ # Find Anvil installation directory
111
+ find_anvil_dir() {
112
+ # Check ANVIL_HOME env var first
113
+ if [ -n "$ANVIL_HOME" ] && [ -d "$ANVIL_HOME" ]; then
114
+ echo "$ANVIL_HOME"
115
+ return 0
116
+ fi
117
+
118
+ # Check if we're in the anvil directory
119
+ if [ -f "./VERSION" ] && [ -d "./global" ]; then
120
+ echo "$(pwd)"
121
+ return 0
122
+ fi
123
+
124
+ # Check common locations
125
+ local locations=(
126
+ "$HOME/Projects/anvil-dev-framework"
127
+ "$HOME/dev/anvil-dev-framework"
128
+ "$HOME/code/anvil-dev-framework"
129
+ "/opt/anvil-dev-framework"
130
+ )
131
+
132
+ for loc in "${locations[@]}"; do
133
+ if [ -f "$loc/VERSION" ]; then
134
+ echo "$loc"
135
+ return 0
136
+ fi
137
+ done
138
+
139
+ return 1
140
+ }
141
+
142
+
143
+ # Get current Anvil version
144
+ get_version() {
145
+ if [ -f "$ANVIL_DIR/VERSION" ]; then
146
+ cat "$ANVIL_DIR/VERSION"
147
+ else
148
+ echo "unknown"
149
+ fi
150
+ }
151
+
152
+ # Compare files and return if different
153
+ files_differ() {
154
+ local src="$1"
155
+ local dst="$2"
156
+
157
+ if [ ! -f "$dst" ]; then
158
+ return 0 # Destination doesn't exist, so "different"
159
+ fi
160
+
161
+ if ! diff -q "$src" "$dst" > /dev/null 2>&1; then
162
+ return 0 # Files differ
163
+ fi
164
+
165
+ return 1 # Files are same
166
+ }
167
+
168
+ # Sync a single file
169
+ sync_file() {
170
+ local src="$1"
171
+ local dst="$2"
172
+ local filename=$(basename "$src")
173
+
174
+ # Check if file exists at destination
175
+ if [ ! -f "$dst" ]; then
176
+ if [ "$DRY_RUN" = true ]; then
177
+ log_dry_run "Would create: $dst"
178
+ else
179
+ mkdir -p "$(dirname "$dst")"
180
+ cp "$src" "$dst"
181
+ echo -e " ${CHECK} Created: ${filename}"
182
+ fi
183
+ return 0
184
+ fi
185
+
186
+ # Check if protected and not forcing
187
+ if is_protected "$filename" && [ "$FORCE" != true ]; then
188
+ if files_differ "$src" "$dst"; then
189
+ echo -e " ${SKIP} Protected (use --force): ${filename}"
190
+ else
191
+ log_verbose "Protected file unchanged: $filename"
192
+ fi
193
+ return 0
194
+ fi
195
+
196
+ # Check if files differ
197
+ if files_differ "$src" "$dst"; then
198
+ if [ "$DRY_RUN" = true ]; then
199
+ log_dry_run "Would update: $dst"
200
+ if [ "$VERBOSE" = true ]; then
201
+ echo -e "${DIM}--- Diff ---${NC}"
202
+ diff "$dst" "$src" || true
203
+ echo -e "${DIM}------------${NC}"
204
+ fi
205
+ else
206
+ cp "$src" "$dst"
207
+ echo -e " ${CHECK} Updated: ${filename}"
208
+ fi
209
+ else
210
+ log_verbose "Unchanged: $filename"
211
+ fi
212
+ }
213
+
214
+ # Sync a directory recursively
215
+ sync_directory() {
216
+ local src_dir="${1%/}" # Remove trailing slash if present
217
+ local dst_dir="${2%/}" # Remove trailing slash if present
218
+ local dir_name=$(basename "$src_dir")
219
+
220
+ if [ ! -d "$src_dir" ]; then
221
+ log_warning "Source directory not found: $src_dir"
222
+ return 1
223
+ fi
224
+
225
+ if [ "$DRY_RUN" = true ]; then
226
+ log_dry_run "Would sync directory: $dir_name/"
227
+ fi
228
+
229
+ mkdir -p "$dst_dir"
230
+
231
+ # Sync all files in directory
232
+ find "$src_dir" -type f | while read -r src_file; do
233
+ local rel_path="${src_file#$src_dir/}"
234
+ local dst_file="$dst_dir/$rel_path"
235
+ sync_file "$src_file" "$dst_file"
236
+ done
237
+ }
238
+
239
+
240
+ #######################################
241
+ # Sync Functions
242
+ #######################################
243
+
244
+ # Sync global config to ~/.claude/
245
+ sync_global() {
246
+ local global_dir="$HOME/.claude"
247
+ local version=$(get_version)
248
+
249
+ echo ""
250
+ echo -e "${BLUE}═══════════════════════════════════════${NC}"
251
+ echo -e "${BLUE} Syncing Global Config (v${version})${NC}"
252
+ echo -e "${BLUE}═══════════════════════════════════════${NC}"
253
+ echo ""
254
+
255
+ # Create directory structure
256
+ mkdir -p "$global_dir/commands"
257
+ mkdir -p "$global_dir/standards"
258
+ mkdir -p "$global_dir/templates"
259
+ mkdir -p "$global_dir/skills"
260
+
261
+ # Sync commands (always update)
262
+ echo -e "${ARROW} Syncing commands..."
263
+ if [ -d "$ANVIL_DIR/global/commands" ]; then
264
+ for cmd in "$ANVIL_DIR/global/commands"/*.md; do
265
+ if [ -f "$cmd" ]; then
266
+ sync_file "$cmd" "$global_dir/commands/$(basename "$cmd")"
267
+ fi
268
+ done
269
+ fi
270
+
271
+ # Sync standards
272
+ echo -e "${ARROW} Syncing standards..."
273
+ if [ -d "$ANVIL_DIR/global/standards" ]; then
274
+ for std in "$ANVIL_DIR/global/standards"/*.md; do
275
+ if [ -f "$std" ]; then
276
+ sync_file "$std" "$global_dir/standards/$(basename "$std")"
277
+ fi
278
+ done
279
+ fi
280
+
281
+ # Sync templates (including subdirectories like ralph/)
282
+ echo -e "${ARROW} Syncing templates..."
283
+ if [ -d "$ANVIL_DIR/global/templates" ]; then
284
+ # Sync top-level template files
285
+ for tpl in "$ANVIL_DIR/global/templates"/*.md; do
286
+ if [ -f "$tpl" ]; then
287
+ sync_file "$tpl" "$global_dir/templates/$(basename "$tpl")"
288
+ fi
289
+ done
290
+ # Sync template subdirectories (e.g., ralph/)
291
+ for subdir in "$ANVIL_DIR/global/templates"/*/; do
292
+ if [ -d "$subdir" ]; then
293
+ local subdir_name=$(basename "$subdir")
294
+ mkdir -p "$global_dir/templates/$subdir_name"
295
+ sync_directory "$subdir" "$global_dir/templates/$subdir_name"
296
+ fi
297
+ done
298
+ fi
299
+
300
+ # Sync global hooks (ralph_stop.sh, etc.)
301
+ echo -e "${ARROW} Syncing global hooks..."
302
+ if [ -d "$ANVIL_DIR/global/hooks" ]; then
303
+ mkdir -p "$global_dir/hooks"
304
+ for hook in "$ANVIL_DIR/global/hooks"/*; do
305
+ if [ -f "$hook" ]; then
306
+ sync_file "$hook" "$global_dir/hooks/$(basename "$hook")"
307
+ fi
308
+ done
309
+ fi
310
+
311
+ # Sync global lib (ralph_state.py, etc.)
312
+ echo -e "${ARROW} Syncing global lib..."
313
+ if [ -d "$ANVIL_DIR/global/lib" ]; then
314
+ mkdir -p "$global_dir/lib"
315
+ for lib in "$ANVIL_DIR/global/lib"/*; do
316
+ if [ -f "$lib" ]; then
317
+ sync_file "$lib" "$global_dir/lib/$(basename "$lib")"
318
+ fi
319
+ done
320
+ fi
321
+
322
+ # Sync global tools (ralph-loop.sh, etc.)
323
+ echo -e "${ARROW} Syncing global tools..."
324
+ if [ -d "$ANVIL_DIR/global/tools" ]; then
325
+ mkdir -p "$global_dir/tools"
326
+ for tool in "$ANVIL_DIR/global/tools"/*; do
327
+ if [ -f "$tool" ]; then
328
+ sync_file "$tool" "$global_dir/tools/$(basename "$tool")"
329
+ fi
330
+ done
331
+ fi
332
+
333
+ # Sync global CLAUDE.md (protected)
334
+ if [ -f "$ANVIL_DIR/global/CLAUDE.md" ]; then
335
+ echo -e "${ARROW} Syncing CLAUDE.md..."
336
+ sync_file "$ANVIL_DIR/global/CLAUDE.md" "$global_dir/CLAUDE.md"
337
+ fi
338
+
339
+ # Update version marker
340
+ if [ "$DRY_RUN" != true ]; then
341
+ echo "$version" > "$global_dir/.anvil-version"
342
+ echo -e " ${CHECK} Version marker updated: v${version}"
343
+ fi
344
+
345
+ echo ""
346
+ log_success "Global sync complete!"
347
+ }
348
+
349
+
350
+ # Sync to a specific project
351
+ sync_project() {
352
+ local project_dir="$1"
353
+ local claude_dir="$project_dir/.claude"
354
+ local version=$(get_version)
355
+
356
+ # Resolve to absolute path
357
+ project_dir=$(cd "$project_dir" && pwd)
358
+ claude_dir="$project_dir/.claude"
359
+
360
+ # Check if project has .claude directory
361
+ if [ ! -d "$claude_dir" ]; then
362
+ log_warning "Project does not have .claude/ directory: $project_dir"
363
+ echo "Run 'anvil init $project_dir' first, or create manually."
364
+ return 1
365
+ fi
366
+
367
+ local project_name=$(basename "$project_dir")
368
+
369
+ echo ""
370
+ echo -e "${BLUE}═══════════════════════════════════════${NC}"
371
+ echo -e "${BLUE} Syncing Project: ${project_name} (v${version})${NC}"
372
+ echo -e "${BLUE}═══════════════════════════════════════${NC}"
373
+ echo ""
374
+
375
+ # Load project config if exists
376
+ local config_file="$claude_dir/.anvil-project.yaml"
377
+
378
+ # Sync hooks (always - critical for functionality)
379
+ echo -e "${ARROW} Syncing hooks..."
380
+ if [ -d "$ANVIL_DIR/project/hooks" ]; then
381
+ sync_directory "$ANVIL_DIR/project/hooks" "$claude_dir/hooks"
382
+ fi
383
+
384
+ # Sync examples (always - reference implementations)
385
+ echo -e "${ARROW} Syncing examples..."
386
+ if [ -d "$ANVIL_DIR/project/examples" ]; then
387
+ sync_directory "$ANVIL_DIR/project/examples" "$claude_dir/examples"
388
+ fi
389
+
390
+ # Sync agents (always - sub-agent definitions)
391
+ echo -e "${ARROW} Syncing agents..."
392
+ if [ -d "$ANVIL_DIR/project/agents" ]; then
393
+ sync_directory "$ANVIL_DIR/project/agents" "$claude_dir/agents"
394
+ fi
395
+
396
+ # Sync retro templates
397
+ echo -e "${ARROW} Syncing retro templates..."
398
+ if [ -d "$ANVIL_DIR/project/retros" ]; then
399
+ mkdir -p "$claude_dir/retros/templates"
400
+ if [ -f "$ANVIL_DIR/project/retros/README.md" ]; then
401
+ sync_file "$ANVIL_DIR/project/retros/README.md" "$claude_dir/retros/README.md"
402
+ fi
403
+ if [ -d "$ANVIL_DIR/project/retros/templates" ]; then
404
+ sync_directory "$ANVIL_DIR/project/retros/templates" "$claude_dir/retros/templates"
405
+ fi
406
+ fi
407
+
408
+ # Sync protected files (only if --force or doesn't exist)
409
+ echo -e "${ARROW} Checking core files..."
410
+
411
+ # CLAUDE.md
412
+ if [ -f "$ANVIL_DIR/project/CLAUDE.md.template" ]; then
413
+ if [ ! -f "$claude_dir/CLAUDE.md" ]; then
414
+ if [ "$DRY_RUN" = true ]; then
415
+ log_dry_run "Would create: CLAUDE.md"
416
+ else
417
+ cp "$ANVIL_DIR/project/CLAUDE.md.template" "$claude_dir/CLAUDE.md"
418
+ echo -e " ${CHECK} Created: CLAUDE.md"
419
+ fi
420
+ else
421
+ echo -e " ${SKIP} Protected: CLAUDE.md (exists)"
422
+ fi
423
+ fi
424
+
425
+ # constitution.md
426
+ if [ -f "$ANVIL_DIR/project/constitution.md.template" ]; then
427
+ if [ ! -f "$claude_dir/constitution.md" ]; then
428
+ if [ "$DRY_RUN" = true ]; then
429
+ log_dry_run "Would create: constitution.md"
430
+ else
431
+ cp "$ANVIL_DIR/project/constitution.md.template" "$claude_dir/constitution.md"
432
+ echo -e " ${CHECK} Created: constitution.md"
433
+ fi
434
+ else
435
+ echo -e " ${SKIP} Protected: constitution.md (exists)"
436
+ fi
437
+ fi
438
+
439
+ # product.md
440
+ if [ -f "$ANVIL_DIR/project/product.md.template" ]; then
441
+ if [ ! -f "$claude_dir/product.md" ]; then
442
+ if [ "$DRY_RUN" = true ]; then
443
+ log_dry_run "Would create: product.md"
444
+ else
445
+ cp "$ANVIL_DIR/project/product.md.template" "$claude_dir/product.md"
446
+ echo -e " ${CHECK} Created: product.md"
447
+ fi
448
+ else
449
+ echo -e " ${SKIP} Protected: product.md (exists)"
450
+ fi
451
+ fi
452
+
453
+ # coordination.md (less protected, sync if newer)
454
+ if [ -f "$ANVIL_DIR/project/coordination.md" ]; then
455
+ sync_file "$ANVIL_DIR/project/coordination.md" "$claude_dir/coordination.md"
456
+ fi
457
+
458
+ # Sync global commands to project (optional - projects can use global)
459
+ echo -e "${ARROW} Syncing commands..."
460
+ if [ -d "$ANVIL_DIR/global/commands" ]; then
461
+ mkdir -p "$claude_dir/commands"
462
+ for cmd in "$ANVIL_DIR/global/commands"/*.md; do
463
+ if [ -f "$cmd" ]; then
464
+ sync_file "$cmd" "$claude_dir/commands/$(basename "$cmd")"
465
+ fi
466
+ done
467
+ fi
468
+
469
+ # Update version marker
470
+ if [ "$DRY_RUN" != true ]; then
471
+ echo "$version" > "$claude_dir/.anvil-version"
472
+ echo -e " ${CHECK} Version marker: v${version}"
473
+ fi
474
+
475
+ echo ""
476
+ log_success "Project sync complete: $project_name"
477
+ }
478
+
479
+
480
+ #######################################
481
+ # Argument Parsing
482
+ #######################################
483
+
484
+ show_help() {
485
+ echo "Anvil Sync - Sync framework updates to global config and projects"
486
+ echo ""
487
+ echo "Usage: $0 [OPTIONS]"
488
+ echo ""
489
+ echo "Targets:"
490
+ echo " --global Sync to ~/.claude/ (global config)"
491
+ echo " --project PATH Sync to a specific project"
492
+ echo " --all Sync global + all registered projects"
493
+ echo ""
494
+ echo "Options:"
495
+ echo " --force, -f Overwrite protected files"
496
+ echo " --dry-run, -n Preview changes without applying"
497
+ echo " --verbose, -v Show detailed output"
498
+ echo " --help, -h Show this help message"
499
+ echo ""
500
+ echo "Examples:"
501
+ echo " $0 --global # Sync global commands"
502
+ echo " $0 --project /path/to/myproject # Sync to specific project"
503
+ echo " $0 --project . --dry-run # Preview project sync"
504
+ echo " $0 --global --project . --force # Full sync with overwrites"
505
+ echo ""
506
+ echo "Protected files (not overwritten without --force):"
507
+ echo " - CLAUDE.md"
508
+ echo " - product.md"
509
+ echo " - constitution.md"
510
+ echo " - settings.local.json"
511
+ echo ""
512
+ echo "Environment:"
513
+ echo " ANVIL_HOME Path to anvil-dev-framework (auto-detected if not set)"
514
+ }
515
+
516
+ parse_args() {
517
+ while [[ $# -gt 0 ]]; do
518
+ case $1 in
519
+ --global)
520
+ SYNC_GLOBAL=true
521
+ shift
522
+ ;;
523
+ --project)
524
+ SYNC_PROJECT="$2"
525
+ shift 2
526
+ ;;
527
+ --all)
528
+ SYNC_ALL=true
529
+ shift
530
+ ;;
531
+ --force|-f)
532
+ FORCE=true
533
+ shift
534
+ ;;
535
+ --dry-run|-n)
536
+ DRY_RUN=true
537
+ shift
538
+ ;;
539
+ --verbose|-v)
540
+ VERBOSE=true
541
+ shift
542
+ ;;
543
+ --help|-h)
544
+ show_help
545
+ exit 0
546
+ ;;
547
+ *)
548
+ log_error "Unknown option: $1"
549
+ show_help
550
+ exit 1
551
+ ;;
552
+ esac
553
+ done
554
+ }
555
+
556
+
557
+ #######################################
558
+ # Main
559
+ #######################################
560
+
561
+ main() {
562
+ parse_args "$@"
563
+
564
+ # Find Anvil directory
565
+ ANVIL_DIR=$(find_anvil_dir)
566
+ if [ -z "$ANVIL_DIR" ]; then
567
+ log_error "Could not find Anvil installation."
568
+ echo "Set ANVIL_HOME environment variable or run from anvil-dev-framework directory."
569
+ exit 1
570
+ fi
571
+
572
+ log_verbose "Anvil directory: $ANVIL_DIR"
573
+
574
+ # Print banner
575
+ print_banner
576
+
577
+ local version=$(get_version)
578
+ echo -e "Anvil Framework v${version}"
579
+ echo -e "Source: ${DIM}${ANVIL_DIR}${NC}"
580
+
581
+ if [ "$DRY_RUN" = true ]; then
582
+ echo -e "${CYAN}Mode: DRY RUN (no changes will be made)${NC}"
583
+ fi
584
+ if [ "$FORCE" = true ]; then
585
+ echo -e "${YELLOW}Mode: FORCE (protected files will be overwritten)${NC}"
586
+ fi
587
+
588
+ # Check if any target specified
589
+ if [ "$SYNC_GLOBAL" != true ] && [ -z "$SYNC_PROJECT" ] && [ "$SYNC_ALL" != true ]; then
590
+ log_error "No sync target specified."
591
+ echo ""
592
+ echo "Use --global, --project PATH, or --all"
593
+ echo "Run '$0 --help' for usage information."
594
+ exit 1
595
+ fi
596
+
597
+ # Execute syncs
598
+ if [ "$SYNC_GLOBAL" = true ] || [ "$SYNC_ALL" = true ]; then
599
+ sync_global
600
+ fi
601
+
602
+ if [ -n "$SYNC_PROJECT" ]; then
603
+ if [ ! -d "$SYNC_PROJECT" ]; then
604
+ log_error "Project directory not found: $SYNC_PROJECT"
605
+ exit 1
606
+ fi
607
+ sync_project "$SYNC_PROJECT"
608
+ fi
609
+
610
+ if [ "$SYNC_ALL" = true ]; then
611
+ # TODO: Read registered projects from ~/.claude/.anvil-projects
612
+ log_warning "--all currently only syncs global. Project registry coming soon."
613
+ fi
614
+
615
+ echo ""
616
+ echo -e "${GREEN}════════════════════════════════════════${NC}"
617
+ echo -e "${GREEN} Sync Complete!${NC}"
618
+ echo -e "${GREEN}════════════════════════════════════════${NC}"
619
+ echo ""
620
+ }
621
+
622
+ # Run main
623
+ main "$@"