agentme 0.1.1

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