@peter.naydenov/morph 3.1.5 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.mocharc.json +1 -0
  2. package/.opencode/command/speckit.analyze.md +184 -0
  3. package/.opencode/command/speckit.checklist.md +294 -0
  4. package/.opencode/command/speckit.clarify.md +181 -0
  5. package/.opencode/command/speckit.constitution.md +82 -0
  6. package/.opencode/command/speckit.implement.md +135 -0
  7. package/.opencode/command/speckit.plan.md +89 -0
  8. package/.opencode/command/speckit.specify.md +257 -0
  9. package/.opencode/command/speckit.tasks.md +137 -0
  10. package/.opencode/command/speckit.taskstoissues.md +28 -0
  11. package/.specify/memory/constitution.md +43 -0
  12. package/.specify/scripts/bash/check-prerequisites.sh +166 -0
  13. package/.specify/scripts/bash/common.sh +156 -0
  14. package/.specify/scripts/bash/create-new-feature.sh +305 -0
  15. package/.specify/scripts/bash/setup-plan.sh +61 -0
  16. package/.specify/scripts/bash/update-agent-context.sh +790 -0
  17. package/.specify/templates/agent-file-template.md +28 -0
  18. package/.specify/templates/checklist-template.md +40 -0
  19. package/.specify/templates/plan-template.md +104 -0
  20. package/.specify/templates/spec-template.md +115 -0
  21. package/.specify/templates/tasks-template.md +251 -0
  22. package/Changelog.md +12 -0
  23. package/README.md +154 -3
  24. package/dist/morph.cjs +1 -1
  25. package/dist/morph.esm.mjs +1 -1
  26. package/dist/morph.umd.js +1 -1
  27. package/morph.png +0 -0
  28. package/package.json +3 -2
  29. package/simple.js +17 -0
  30. package/specs/001-extend-templates/checklists/requirements.md +35 -0
  31. package/specs/001-extend-templates/contracts/set-method.json +39 -0
  32. package/specs/001-extend-templates/data-model.md +76 -0
  33. package/specs/001-extend-templates/plan.md +90 -0
  34. package/specs/001-extend-templates/quickstart.md +56 -0
  35. package/specs/001-extend-templates/research.md +18 -0
  36. package/specs/001-extend-templates/spec.md +139 -0
  37. package/specs/001-extend-templates/tasks.md +255 -0
  38. package/src/methods/_readTemplate.js +22 -46
  39. package/src/methods/_setupActions.js +1 -8
  40. package/src/methods/build.js +98 -43
  41. package/src/methods/render.js +14 -11
@@ -0,0 +1,790 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Update agent context files with information from plan.md
4
+ #
5
+ # This script maintains AI agent context files by parsing feature specifications
6
+ # and updating agent-specific configuration files with project information.
7
+ #
8
+ # MAIN FUNCTIONS:
9
+ # 1. Environment Validation
10
+ # - Verifies git repository structure and branch information
11
+ # - Checks for required plan.md files and templates
12
+ # - Validates file permissions and accessibility
13
+ #
14
+ # 2. Plan Data Extraction
15
+ # - Parses plan.md files to extract project metadata
16
+ # - Identifies language/version, frameworks, databases, and project types
17
+ # - Handles missing or incomplete specification data gracefully
18
+ #
19
+ # 3. Agent File Management
20
+ # - Creates new agent context files from templates when needed
21
+ # - Updates existing agent files with new project information
22
+ # - Preserves manual additions and custom configurations
23
+ # - Supports multiple AI agent formats and directory structures
24
+ #
25
+ # 4. Content Generation
26
+ # - Generates language-specific build/test commands
27
+ # - Creates appropriate project directory structures
28
+ # - Updates technology stacks and recent changes sections
29
+ # - Maintains consistent formatting and timestamps
30
+ #
31
+ # 5. Multi-Agent Support
32
+ # - Handles agent-specific file paths and naming conventions
33
+ # - Supports: Claude, Gemini, Copilot, Cursor, Qwen, opencode, Codex, Windsurf, Kilo Code, Auggie CLI, Roo Code, CodeBuddy CLI, Amp, SHAI, or Amazon Q Developer CLI
34
+ # - Can update single agents or all existing agent files
35
+ # - Creates default Claude file if no agent files exist
36
+ #
37
+ # Usage: ./update-agent-context.sh [agent_type]
38
+ # Agent types: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|shai|q|bob
39
+ # Leave empty to update all existing agent files
40
+
41
+ set -e
42
+
43
+ # Enable strict error handling
44
+ set -u
45
+ set -o pipefail
46
+
47
+ #==============================================================================
48
+ # Configuration and Global Variables
49
+ #==============================================================================
50
+
51
+ # Get script directory and load common functions
52
+ SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
53
+ source "$SCRIPT_DIR/common.sh"
54
+
55
+ # Get all paths and variables from common functions
56
+ eval $(get_feature_paths)
57
+
58
+ NEW_PLAN="$IMPL_PLAN" # Alias for compatibility with existing code
59
+ AGENT_TYPE="${1:-}"
60
+
61
+ # Agent-specific file paths
62
+ CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"
63
+ GEMINI_FILE="$REPO_ROOT/GEMINI.md"
64
+ COPILOT_FILE="$REPO_ROOT/.github/agents/copilot-instructions.md"
65
+ CURSOR_FILE="$REPO_ROOT/.cursor/rules/specify-rules.mdc"
66
+ QWEN_FILE="$REPO_ROOT/QWEN.md"
67
+ AGENTS_FILE="$REPO_ROOT/AGENTS.md"
68
+ WINDSURF_FILE="$REPO_ROOT/.windsurf/rules/specify-rules.md"
69
+ KILOCODE_FILE="$REPO_ROOT/.kilocode/rules/specify-rules.md"
70
+ AUGGIE_FILE="$REPO_ROOT/.augment/rules/specify-rules.md"
71
+ ROO_FILE="$REPO_ROOT/.roo/rules/specify-rules.md"
72
+ CODEBUDDY_FILE="$REPO_ROOT/CODEBUDDY.md"
73
+ AMP_FILE="$REPO_ROOT/AGENTS.md"
74
+ SHAI_FILE="$REPO_ROOT/SHAI.md"
75
+ Q_FILE="$REPO_ROOT/AGENTS.md"
76
+ BOB_FILE="$REPO_ROOT/AGENTS.md"
77
+
78
+ # Template file
79
+ TEMPLATE_FILE="$REPO_ROOT/.specify/templates/agent-file-template.md"
80
+
81
+ # Global variables for parsed plan data
82
+ NEW_LANG=""
83
+ NEW_FRAMEWORK=""
84
+ NEW_DB=""
85
+ NEW_PROJECT_TYPE=""
86
+
87
+ #==============================================================================
88
+ # Utility Functions
89
+ #==============================================================================
90
+
91
+ log_info() {
92
+ echo "INFO: $1"
93
+ }
94
+
95
+ log_success() {
96
+ echo "✓ $1"
97
+ }
98
+
99
+ log_error() {
100
+ echo "ERROR: $1" >&2
101
+ }
102
+
103
+ log_warning() {
104
+ echo "WARNING: $1" >&2
105
+ }
106
+
107
+ # Cleanup function for temporary files
108
+ cleanup() {
109
+ local exit_code=$?
110
+ rm -f /tmp/agent_update_*_$$
111
+ rm -f /tmp/manual_additions_$$
112
+ exit $exit_code
113
+ }
114
+
115
+ # Set up cleanup trap
116
+ trap cleanup EXIT INT TERM
117
+
118
+ #==============================================================================
119
+ # Validation Functions
120
+ #==============================================================================
121
+
122
+ validate_environment() {
123
+ # Check if we have a current branch/feature (git or non-git)
124
+ if [[ -z "$CURRENT_BRANCH" ]]; then
125
+ log_error "Unable to determine current feature"
126
+ if [[ "$HAS_GIT" == "true" ]]; then
127
+ log_info "Make sure you're on a feature branch"
128
+ else
129
+ log_info "Set SPECIFY_FEATURE environment variable or create a feature first"
130
+ fi
131
+ exit 1
132
+ fi
133
+
134
+ # Check if plan.md exists
135
+ if [[ ! -f "$NEW_PLAN" ]]; then
136
+ log_error "No plan.md found at $NEW_PLAN"
137
+ log_info "Make sure you're working on a feature with a corresponding spec directory"
138
+ if [[ "$HAS_GIT" != "true" ]]; then
139
+ log_info "Use: export SPECIFY_FEATURE=your-feature-name or create a new feature first"
140
+ fi
141
+ exit 1
142
+ fi
143
+
144
+ # Check if template exists (needed for new files)
145
+ if [[ ! -f "$TEMPLATE_FILE" ]]; then
146
+ log_warning "Template file not found at $TEMPLATE_FILE"
147
+ log_warning "Creating new agent files will fail"
148
+ fi
149
+ }
150
+
151
+ #==============================================================================
152
+ # Plan Parsing Functions
153
+ #==============================================================================
154
+
155
+ extract_plan_field() {
156
+ local field_pattern="$1"
157
+ local plan_file="$2"
158
+
159
+ grep "^\*\*${field_pattern}\*\*: " "$plan_file" 2>/dev/null | \
160
+ head -1 | \
161
+ sed "s|^\*\*${field_pattern}\*\*: ||" | \
162
+ sed 's/^[ \t]*//;s/[ \t]*$//' | \
163
+ grep -v "NEEDS CLARIFICATION" | \
164
+ grep -v "^N/A$" || echo ""
165
+ }
166
+
167
+ parse_plan_data() {
168
+ local plan_file="$1"
169
+
170
+ if [[ ! -f "$plan_file" ]]; then
171
+ log_error "Plan file not found: $plan_file"
172
+ return 1
173
+ fi
174
+
175
+ if [[ ! -r "$plan_file" ]]; then
176
+ log_error "Plan file is not readable: $plan_file"
177
+ return 1
178
+ fi
179
+
180
+ log_info "Parsing plan data from $plan_file"
181
+
182
+ NEW_LANG=$(extract_plan_field "Language/Version" "$plan_file")
183
+ NEW_FRAMEWORK=$(extract_plan_field "Primary Dependencies" "$plan_file")
184
+ NEW_DB=$(extract_plan_field "Storage" "$plan_file")
185
+ NEW_PROJECT_TYPE=$(extract_plan_field "Project Type" "$plan_file")
186
+
187
+ # Log what we found
188
+ if [[ -n "$NEW_LANG" ]]; then
189
+ log_info "Found language: $NEW_LANG"
190
+ else
191
+ log_warning "No language information found in plan"
192
+ fi
193
+
194
+ if [[ -n "$NEW_FRAMEWORK" ]]; then
195
+ log_info "Found framework: $NEW_FRAMEWORK"
196
+ fi
197
+
198
+ if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]]; then
199
+ log_info "Found database: $NEW_DB"
200
+ fi
201
+
202
+ if [[ -n "$NEW_PROJECT_TYPE" ]]; then
203
+ log_info "Found project type: $NEW_PROJECT_TYPE"
204
+ fi
205
+ }
206
+
207
+ format_technology_stack() {
208
+ local lang="$1"
209
+ local framework="$2"
210
+ local parts=()
211
+
212
+ # Add non-empty parts
213
+ [[ -n "$lang" && "$lang" != "NEEDS CLARIFICATION" ]] && parts+=("$lang")
214
+ [[ -n "$framework" && "$framework" != "NEEDS CLARIFICATION" && "$framework" != "N/A" ]] && parts+=("$framework")
215
+
216
+ # Join with proper formatting
217
+ if [[ ${#parts[@]} -eq 0 ]]; then
218
+ echo ""
219
+ elif [[ ${#parts[@]} -eq 1 ]]; then
220
+ echo "${parts[0]}"
221
+ else
222
+ # Join multiple parts with " + "
223
+ local result="${parts[0]}"
224
+ for ((i=1; i<${#parts[@]}; i++)); do
225
+ result="$result + ${parts[i]}"
226
+ done
227
+ echo "$result"
228
+ fi
229
+ }
230
+
231
+ #==============================================================================
232
+ # Template and Content Generation Functions
233
+ #==============================================================================
234
+
235
+ get_project_structure() {
236
+ local project_type="$1"
237
+
238
+ if [[ "$project_type" == *"web"* ]]; then
239
+ echo "backend/\\nfrontend/\\ntests/"
240
+ else
241
+ echo "src/\\ntests/"
242
+ fi
243
+ }
244
+
245
+ get_commands_for_language() {
246
+ local lang="$1"
247
+
248
+ case "$lang" in
249
+ *"Python"*)
250
+ echo "cd src && pytest && ruff check ."
251
+ ;;
252
+ *"Rust"*)
253
+ echo "cargo test && cargo clippy"
254
+ ;;
255
+ *"JavaScript"*|*"TypeScript"*)
256
+ echo "npm test \\&\\& npm run lint"
257
+ ;;
258
+ *)
259
+ echo "# Add commands for $lang"
260
+ ;;
261
+ esac
262
+ }
263
+
264
+ get_language_conventions() {
265
+ local lang="$1"
266
+ echo "$lang: Follow standard conventions"
267
+ }
268
+
269
+ create_new_agent_file() {
270
+ local target_file="$1"
271
+ local temp_file="$2"
272
+ local project_name="$3"
273
+ local current_date="$4"
274
+
275
+ if [[ ! -f "$TEMPLATE_FILE" ]]; then
276
+ log_error "Template not found at $TEMPLATE_FILE"
277
+ return 1
278
+ fi
279
+
280
+ if [[ ! -r "$TEMPLATE_FILE" ]]; then
281
+ log_error "Template file is not readable: $TEMPLATE_FILE"
282
+ return 1
283
+ fi
284
+
285
+ log_info "Creating new agent context file from template..."
286
+
287
+ if ! cp "$TEMPLATE_FILE" "$temp_file"; then
288
+ log_error "Failed to copy template file"
289
+ return 1
290
+ fi
291
+
292
+ # Replace template placeholders
293
+ local project_structure
294
+ project_structure=$(get_project_structure "$NEW_PROJECT_TYPE")
295
+
296
+ local commands
297
+ commands=$(get_commands_for_language "$NEW_LANG")
298
+
299
+ local language_conventions
300
+ language_conventions=$(get_language_conventions "$NEW_LANG")
301
+
302
+ # Perform substitutions with error checking using safer approach
303
+ # Escape special characters for sed by using a different delimiter or escaping
304
+ local escaped_lang=$(printf '%s\n' "$NEW_LANG" | sed 's/[\[\.*^$()+{}|]/\\&/g')
305
+ local escaped_framework=$(printf '%s\n' "$NEW_FRAMEWORK" | sed 's/[\[\.*^$()+{}|]/\\&/g')
306
+ local escaped_branch=$(printf '%s\n' "$CURRENT_BRANCH" | sed 's/[\[\.*^$()+{}|]/\\&/g')
307
+
308
+ # Build technology stack and recent change strings conditionally
309
+ local tech_stack
310
+ if [[ -n "$escaped_lang" && -n "$escaped_framework" ]]; then
311
+ tech_stack="- $escaped_lang + $escaped_framework ($escaped_branch)"
312
+ elif [[ -n "$escaped_lang" ]]; then
313
+ tech_stack="- $escaped_lang ($escaped_branch)"
314
+ elif [[ -n "$escaped_framework" ]]; then
315
+ tech_stack="- $escaped_framework ($escaped_branch)"
316
+ else
317
+ tech_stack="- ($escaped_branch)"
318
+ fi
319
+
320
+ local recent_change
321
+ if [[ -n "$escaped_lang" && -n "$escaped_framework" ]]; then
322
+ recent_change="- $escaped_branch: Added $escaped_lang + $escaped_framework"
323
+ elif [[ -n "$escaped_lang" ]]; then
324
+ recent_change="- $escaped_branch: Added $escaped_lang"
325
+ elif [[ -n "$escaped_framework" ]]; then
326
+ recent_change="- $escaped_branch: Added $escaped_framework"
327
+ else
328
+ recent_change="- $escaped_branch: Added"
329
+ fi
330
+
331
+ local substitutions=(
332
+ "s|\[PROJECT NAME\]|$project_name|"
333
+ "s|\[DATE\]|$current_date|"
334
+ "s|\[EXTRACTED FROM ALL PLAN.MD FILES\]|$tech_stack|"
335
+ "s|\[ACTUAL STRUCTURE FROM PLANS\]|$project_structure|g"
336
+ "s|\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]|$commands|"
337
+ "s|\[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE\]|$language_conventions|"
338
+ "s|\[LAST 3 FEATURES AND WHAT THEY ADDED\]|$recent_change|"
339
+ )
340
+
341
+ for substitution in "${substitutions[@]}"; do
342
+ if ! sed -i.bak -e "$substitution" "$temp_file"; then
343
+ log_error "Failed to perform substitution: $substitution"
344
+ rm -f "$temp_file" "$temp_file.bak"
345
+ return 1
346
+ fi
347
+ done
348
+
349
+ # Convert \n sequences to actual newlines
350
+ newline=$(printf '\n')
351
+ sed -i.bak2 "s/\\\\n/${newline}/g" "$temp_file"
352
+
353
+ # Clean up backup files
354
+ rm -f "$temp_file.bak" "$temp_file.bak2"
355
+
356
+ return 0
357
+ }
358
+
359
+
360
+
361
+
362
+ update_existing_agent_file() {
363
+ local target_file="$1"
364
+ local current_date="$2"
365
+
366
+ log_info "Updating existing agent context file..."
367
+
368
+ # Use a single temporary file for atomic update
369
+ local temp_file
370
+ temp_file=$(mktemp) || {
371
+ log_error "Failed to create temporary file"
372
+ return 1
373
+ }
374
+
375
+ # Process the file in one pass
376
+ local tech_stack=$(format_technology_stack "$NEW_LANG" "$NEW_FRAMEWORK")
377
+ local new_tech_entries=()
378
+ local new_change_entry=""
379
+
380
+ # Prepare new technology entries
381
+ if [[ -n "$tech_stack" ]] && ! grep -q "$tech_stack" "$target_file"; then
382
+ new_tech_entries+=("- $tech_stack ($CURRENT_BRANCH)")
383
+ fi
384
+
385
+ if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]] && [[ "$NEW_DB" != "NEEDS CLARIFICATION" ]] && ! grep -q "$NEW_DB" "$target_file"; then
386
+ new_tech_entries+=("- $NEW_DB ($CURRENT_BRANCH)")
387
+ fi
388
+
389
+ # Prepare new change entry
390
+ if [[ -n "$tech_stack" ]]; then
391
+ new_change_entry="- $CURRENT_BRANCH: Added $tech_stack"
392
+ elif [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]] && [[ "$NEW_DB" != "NEEDS CLARIFICATION" ]]; then
393
+ new_change_entry="- $CURRENT_BRANCH: Added $NEW_DB"
394
+ fi
395
+
396
+ # Check if sections exist in the file
397
+ local has_active_technologies=0
398
+ local has_recent_changes=0
399
+
400
+ if grep -q "^## Active Technologies" "$target_file" 2>/dev/null; then
401
+ has_active_technologies=1
402
+ fi
403
+
404
+ if grep -q "^## Recent Changes" "$target_file" 2>/dev/null; then
405
+ has_recent_changes=1
406
+ fi
407
+
408
+ # Process file line by line
409
+ local in_tech_section=false
410
+ local in_changes_section=false
411
+ local tech_entries_added=false
412
+ local changes_entries_added=false
413
+ local existing_changes_count=0
414
+ local file_ended=false
415
+
416
+ while IFS= read -r line || [[ -n "$line" ]]; do
417
+ # Handle Active Technologies section
418
+ if [[ "$line" == "## Active Technologies" ]]; then
419
+ echo "$line" >> "$temp_file"
420
+ in_tech_section=true
421
+ continue
422
+ elif [[ $in_tech_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then
423
+ # Add new tech entries before closing the section
424
+ if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
425
+ printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
426
+ tech_entries_added=true
427
+ fi
428
+ echo "$line" >> "$temp_file"
429
+ in_tech_section=false
430
+ continue
431
+ elif [[ $in_tech_section == true ]] && [[ -z "$line" ]]; then
432
+ # Add new tech entries before empty line in tech section
433
+ if [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
434
+ printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
435
+ tech_entries_added=true
436
+ fi
437
+ echo "$line" >> "$temp_file"
438
+ continue
439
+ fi
440
+
441
+ # Handle Recent Changes section
442
+ if [[ "$line" == "## Recent Changes" ]]; then
443
+ echo "$line" >> "$temp_file"
444
+ # Add new change entry right after the heading
445
+ if [[ -n "$new_change_entry" ]]; then
446
+ echo "$new_change_entry" >> "$temp_file"
447
+ fi
448
+ in_changes_section=true
449
+ changes_entries_added=true
450
+ continue
451
+ elif [[ $in_changes_section == true ]] && [[ "$line" =~ ^##[[:space:]] ]]; then
452
+ echo "$line" >> "$temp_file"
453
+ in_changes_section=false
454
+ continue
455
+ elif [[ $in_changes_section == true ]] && [[ "$line" == "- "* ]]; then
456
+ # Keep only first 2 existing changes
457
+ if [[ $existing_changes_count -lt 2 ]]; then
458
+ echo "$line" >> "$temp_file"
459
+ ((existing_changes_count++))
460
+ fi
461
+ continue
462
+ fi
463
+
464
+ # Update timestamp
465
+ if [[ "$line" =~ \*\*Last\ updated\*\*:.*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] ]]; then
466
+ echo "$line" | sed "s/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/$current_date/" >> "$temp_file"
467
+ else
468
+ echo "$line" >> "$temp_file"
469
+ fi
470
+ done < "$target_file"
471
+
472
+ # Post-loop check: if we're still in the Active Technologies section and haven't added new entries
473
+ if [[ $in_tech_section == true ]] && [[ $tech_entries_added == false ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
474
+ printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
475
+ tech_entries_added=true
476
+ fi
477
+
478
+ # If sections don't exist, add them at the end of the file
479
+ if [[ $has_active_technologies -eq 0 ]] && [[ ${#new_tech_entries[@]} -gt 0 ]]; then
480
+ echo "" >> "$temp_file"
481
+ echo "## Active Technologies" >> "$temp_file"
482
+ printf '%s\n' "${new_tech_entries[@]}" >> "$temp_file"
483
+ tech_entries_added=true
484
+ fi
485
+
486
+ if [[ $has_recent_changes -eq 0 ]] && [[ -n "$new_change_entry" ]]; then
487
+ echo "" >> "$temp_file"
488
+ echo "## Recent Changes" >> "$temp_file"
489
+ echo "$new_change_entry" >> "$temp_file"
490
+ changes_entries_added=true
491
+ fi
492
+
493
+ # Move temp file to target atomically
494
+ if ! mv "$temp_file" "$target_file"; then
495
+ log_error "Failed to update target file"
496
+ rm -f "$temp_file"
497
+ return 1
498
+ fi
499
+
500
+ return 0
501
+ }
502
+ #==============================================================================
503
+ # Main Agent File Update Function
504
+ #==============================================================================
505
+
506
+ update_agent_file() {
507
+ local target_file="$1"
508
+ local agent_name="$2"
509
+
510
+ if [[ -z "$target_file" ]] || [[ -z "$agent_name" ]]; then
511
+ log_error "update_agent_file requires target_file and agent_name parameters"
512
+ return 1
513
+ fi
514
+
515
+ log_info "Updating $agent_name context file: $target_file"
516
+
517
+ local project_name
518
+ project_name=$(basename "$REPO_ROOT")
519
+ local current_date
520
+ current_date=$(date +%Y-%m-%d)
521
+
522
+ # Create directory if it doesn't exist
523
+ local target_dir
524
+ target_dir=$(dirname "$target_file")
525
+ if [[ ! -d "$target_dir" ]]; then
526
+ if ! mkdir -p "$target_dir"; then
527
+ log_error "Failed to create directory: $target_dir"
528
+ return 1
529
+ fi
530
+ fi
531
+
532
+ if [[ ! -f "$target_file" ]]; then
533
+ # Create new file from template
534
+ local temp_file
535
+ temp_file=$(mktemp) || {
536
+ log_error "Failed to create temporary file"
537
+ return 1
538
+ }
539
+
540
+ if create_new_agent_file "$target_file" "$temp_file" "$project_name" "$current_date"; then
541
+ if mv "$temp_file" "$target_file"; then
542
+ log_success "Created new $agent_name context file"
543
+ else
544
+ log_error "Failed to move temporary file to $target_file"
545
+ rm -f "$temp_file"
546
+ return 1
547
+ fi
548
+ else
549
+ log_error "Failed to create new agent file"
550
+ rm -f "$temp_file"
551
+ return 1
552
+ fi
553
+ else
554
+ # Update existing file
555
+ if [[ ! -r "$target_file" ]]; then
556
+ log_error "Cannot read existing file: $target_file"
557
+ return 1
558
+ fi
559
+
560
+ if [[ ! -w "$target_file" ]]; then
561
+ log_error "Cannot write to existing file: $target_file"
562
+ return 1
563
+ fi
564
+
565
+ if update_existing_agent_file "$target_file" "$current_date"; then
566
+ log_success "Updated existing $agent_name context file"
567
+ else
568
+ log_error "Failed to update existing agent file"
569
+ return 1
570
+ fi
571
+ fi
572
+
573
+ return 0
574
+ }
575
+
576
+ #==============================================================================
577
+ # Agent Selection and Processing
578
+ #==============================================================================
579
+
580
+ update_specific_agent() {
581
+ local agent_type="$1"
582
+
583
+ case "$agent_type" in
584
+ claude)
585
+ update_agent_file "$CLAUDE_FILE" "Claude Code"
586
+ ;;
587
+ gemini)
588
+ update_agent_file "$GEMINI_FILE" "Gemini CLI"
589
+ ;;
590
+ copilot)
591
+ update_agent_file "$COPILOT_FILE" "GitHub Copilot"
592
+ ;;
593
+ cursor-agent)
594
+ update_agent_file "$CURSOR_FILE" "Cursor IDE"
595
+ ;;
596
+ qwen)
597
+ update_agent_file "$QWEN_FILE" "Qwen Code"
598
+ ;;
599
+ opencode)
600
+ update_agent_file "$AGENTS_FILE" "opencode"
601
+ ;;
602
+ codex)
603
+ update_agent_file "$AGENTS_FILE" "Codex CLI"
604
+ ;;
605
+ windsurf)
606
+ update_agent_file "$WINDSURF_FILE" "Windsurf"
607
+ ;;
608
+ kilocode)
609
+ update_agent_file "$KILOCODE_FILE" "Kilo Code"
610
+ ;;
611
+ auggie)
612
+ update_agent_file "$AUGGIE_FILE" "Auggie CLI"
613
+ ;;
614
+ roo)
615
+ update_agent_file "$ROO_FILE" "Roo Code"
616
+ ;;
617
+ codebuddy)
618
+ update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
619
+ ;;
620
+ amp)
621
+ update_agent_file "$AMP_FILE" "Amp"
622
+ ;;
623
+ shai)
624
+ update_agent_file "$SHAI_FILE" "SHAI"
625
+ ;;
626
+ q)
627
+ update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
628
+ ;;
629
+ bob)
630
+ update_agent_file "$BOB_FILE" "IBM Bob"
631
+ ;;
632
+ *)
633
+ log_error "Unknown agent type '$agent_type'"
634
+ log_error "Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|amp|shai|q|bob"
635
+ exit 1
636
+ ;;
637
+ esac
638
+ }
639
+
640
+ update_all_existing_agents() {
641
+ local found_agent=false
642
+
643
+ # Check each possible agent file and update if it exists
644
+ if [[ -f "$CLAUDE_FILE" ]]; then
645
+ update_agent_file "$CLAUDE_FILE" "Claude Code"
646
+ found_agent=true
647
+ fi
648
+
649
+ if [[ -f "$GEMINI_FILE" ]]; then
650
+ update_agent_file "$GEMINI_FILE" "Gemini CLI"
651
+ found_agent=true
652
+ fi
653
+
654
+ if [[ -f "$COPILOT_FILE" ]]; then
655
+ update_agent_file "$COPILOT_FILE" "GitHub Copilot"
656
+ found_agent=true
657
+ fi
658
+
659
+ if [[ -f "$CURSOR_FILE" ]]; then
660
+ update_agent_file "$CURSOR_FILE" "Cursor IDE"
661
+ found_agent=true
662
+ fi
663
+
664
+ if [[ -f "$QWEN_FILE" ]]; then
665
+ update_agent_file "$QWEN_FILE" "Qwen Code"
666
+ found_agent=true
667
+ fi
668
+
669
+ if [[ -f "$AGENTS_FILE" ]]; then
670
+ update_agent_file "$AGENTS_FILE" "Codex/opencode"
671
+ found_agent=true
672
+ fi
673
+
674
+ if [[ -f "$WINDSURF_FILE" ]]; then
675
+ update_agent_file "$WINDSURF_FILE" "Windsurf"
676
+ found_agent=true
677
+ fi
678
+
679
+ if [[ -f "$KILOCODE_FILE" ]]; then
680
+ update_agent_file "$KILOCODE_FILE" "Kilo Code"
681
+ found_agent=true
682
+ fi
683
+
684
+ if [[ -f "$AUGGIE_FILE" ]]; then
685
+ update_agent_file "$AUGGIE_FILE" "Auggie CLI"
686
+ found_agent=true
687
+ fi
688
+
689
+ if [[ -f "$ROO_FILE" ]]; then
690
+ update_agent_file "$ROO_FILE" "Roo Code"
691
+ found_agent=true
692
+ fi
693
+
694
+ if [[ -f "$CODEBUDDY_FILE" ]]; then
695
+ update_agent_file "$CODEBUDDY_FILE" "CodeBuddy CLI"
696
+ found_agent=true
697
+ fi
698
+
699
+ if [[ -f "$SHAI_FILE" ]]; then
700
+ update_agent_file "$SHAI_FILE" "SHAI"
701
+ found_agent=true
702
+ fi
703
+
704
+ if [[ -f "$Q_FILE" ]]; then
705
+ update_agent_file "$Q_FILE" "Amazon Q Developer CLI"
706
+ found_agent=true
707
+ fi
708
+
709
+ if [[ -f "$BOB_FILE" ]]; then
710
+ update_agent_file "$BOB_FILE" "IBM Bob"
711
+ found_agent=true
712
+ fi
713
+
714
+ # If no agent files exist, create a default Claude file
715
+ if [[ "$found_agent" == false ]]; then
716
+ log_info "No existing agent files found, creating default Claude file..."
717
+ update_agent_file "$CLAUDE_FILE" "Claude Code"
718
+ fi
719
+ }
720
+ print_summary() {
721
+ echo
722
+ log_info "Summary of changes:"
723
+
724
+ if [[ -n "$NEW_LANG" ]]; then
725
+ echo " - Added language: $NEW_LANG"
726
+ fi
727
+
728
+ if [[ -n "$NEW_FRAMEWORK" ]]; then
729
+ echo " - Added framework: $NEW_FRAMEWORK"
730
+ fi
731
+
732
+ if [[ -n "$NEW_DB" ]] && [[ "$NEW_DB" != "N/A" ]]; then
733
+ echo " - Added database: $NEW_DB"
734
+ fi
735
+
736
+ echo
737
+
738
+ log_info "Usage: $0 [claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|codebuddy|shai|q|bob]"
739
+ }
740
+
741
+ #==============================================================================
742
+ # Main Execution
743
+ #==============================================================================
744
+
745
+ main() {
746
+ # Validate environment before proceeding
747
+ validate_environment
748
+
749
+ log_info "=== Updating agent context files for feature $CURRENT_BRANCH ==="
750
+
751
+ # Parse the plan file to extract project information
752
+ if ! parse_plan_data "$NEW_PLAN"; then
753
+ log_error "Failed to parse plan data"
754
+ exit 1
755
+ fi
756
+
757
+ # Process based on agent type argument
758
+ local success=true
759
+
760
+ if [[ -z "$AGENT_TYPE" ]]; then
761
+ # No specific agent provided - update all existing agent files
762
+ log_info "No agent specified, updating all existing agent files..."
763
+ if ! update_all_existing_agents; then
764
+ success=false
765
+ fi
766
+ else
767
+ # Specific agent provided - update only that agent
768
+ log_info "Updating specific agent: $AGENT_TYPE"
769
+ if ! update_specific_agent "$AGENT_TYPE"; then
770
+ success=false
771
+ fi
772
+ fi
773
+
774
+ # Print summary
775
+ print_summary
776
+
777
+ if [[ "$success" == true ]]; then
778
+ log_success "Agent context update completed successfully"
779
+ exit 0
780
+ else
781
+ log_error "Agent context update completed with errors"
782
+ exit 1
783
+ fi
784
+ }
785
+
786
+ # Execute main function if script is run directly
787
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
788
+ main "$@"
789
+ fi
790
+