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