@techwavedev/agi-agent-kit 1.1.3

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 (196) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +147 -0
  3. package/bin/init.js +471 -0
  4. package/package.json +36 -0
  5. package/templates/.agent/agents/backend-specialist.md +263 -0
  6. package/templates/.agent/agents/code-archaeologist.md +106 -0
  7. package/templates/.agent/agents/database-architect.md +226 -0
  8. package/templates/.agent/agents/debugger.md +225 -0
  9. package/templates/.agent/agents/devops-engineer.md +242 -0
  10. package/templates/.agent/agents/documentation-writer.md +104 -0
  11. package/templates/.agent/agents/explorer-agent.md +73 -0
  12. package/templates/.agent/agents/frontend-specialist.md +556 -0
  13. package/templates/.agent/agents/game-developer.md +162 -0
  14. package/templates/.agent/agents/mobile-developer.md +377 -0
  15. package/templates/.agent/agents/orchestrator.md +416 -0
  16. package/templates/.agent/agents/penetration-tester.md +188 -0
  17. package/templates/.agent/agents/performance-optimizer.md +187 -0
  18. package/templates/.agent/agents/product-manager.md +112 -0
  19. package/templates/.agent/agents/project-planner.md +403 -0
  20. package/templates/.agent/agents/qa-automation-engineer.md +109 -0
  21. package/templates/.agent/agents/security-auditor.md +170 -0
  22. package/templates/.agent/agents/seo-specialist.md +111 -0
  23. package/templates/.agent/agents/test-engineer.md +158 -0
  24. package/templates/.agent/rules/GEMINI.md +253 -0
  25. package/templates/.agent/workflows/brainstorm.md +113 -0
  26. package/templates/.agent/workflows/create.md +59 -0
  27. package/templates/.agent/workflows/debug.md +103 -0
  28. package/templates/.agent/workflows/deploy.md +176 -0
  29. package/templates/.agent/workflows/enhance.md +63 -0
  30. package/templates/.agent/workflows/orchestrate.md +237 -0
  31. package/templates/.agent/workflows/plan.md +89 -0
  32. package/templates/.agent/workflows/preview.md +81 -0
  33. package/templates/.agent/workflows/status.md +86 -0
  34. package/templates/.agent/workflows/test.md +144 -0
  35. package/templates/.agent/workflows/ui-ux-pro-max.md +296 -0
  36. package/templates/base/.env.example +54 -0
  37. package/templates/base/AGENTS.md +463 -0
  38. package/templates/base/requirements.txt +6 -0
  39. package/templates/base/skill-creator/LICENSE.txt +202 -0
  40. package/templates/base/skill-creator/SKILL_skillcreator.md +389 -0
  41. package/templates/base/skill-creator/references/output-patterns.md +82 -0
  42. package/templates/base/skill-creator/references/workflows.md +28 -0
  43. package/templates/base/skill-creator/scripts/init_skill.py +304 -0
  44. package/templates/base/skill-creator/scripts/package_skill.py +110 -0
  45. package/templates/base/skill-creator/scripts/quick_validate.py +95 -0
  46. package/templates/base/skill-creator/scripts/update_catalog.py +371 -0
  47. package/templates/skills/core/README.md +21 -0
  48. package/templates/skills/core/documentation/SKILL.md +351 -0
  49. package/templates/skills/core/documentation/references/best_practices.md +201 -0
  50. package/templates/skills/core/documentation/scripts/analyze_code.py +307 -0
  51. package/templates/skills/core/documentation/scripts/detect_changes.py +460 -0
  52. package/templates/skills/core/documentation/scripts/generate_changelog.py +312 -0
  53. package/templates/skills/core/documentation/scripts/sync_docs.py +272 -0
  54. package/templates/skills/core/documentation/scripts/update_skill_docs.py +366 -0
  55. package/templates/skills/core/pdf-reader/SKILL.md +104 -0
  56. package/templates/skills/core/pdf-reader/references/pdf_libraries.md +83 -0
  57. package/templates/skills/core/pdf-reader/scripts/extract_text.py +295 -0
  58. package/templates/skills/core/qdrant-memory/SKILL.md +435 -0
  59. package/templates/skills/core/qdrant-memory/references/advanced_patterns.md +375 -0
  60. package/templates/skills/core/qdrant-memory/references/collection_schemas.md +229 -0
  61. package/templates/skills/core/qdrant-memory/references/complete_guide.md +724 -0
  62. package/templates/skills/core/qdrant-memory/references/embedding_models.md +325 -0
  63. package/templates/skills/core/qdrant-memory/scripts/benchmark_token_savings.py +640 -0
  64. package/templates/skills/core/qdrant-memory/scripts/embedding_utils.py +323 -0
  65. package/templates/skills/core/qdrant-memory/scripts/hybrid_search.py +214 -0
  66. package/templates/skills/core/qdrant-memory/scripts/init_collection.py +193 -0
  67. package/templates/skills/core/qdrant-memory/scripts/memory_retrieval.py +345 -0
  68. package/templates/skills/core/qdrant-memory/scripts/semantic_cache.py +282 -0
  69. package/templates/skills/core/qdrant-memory/scripts/test_skill.py +655 -0
  70. package/templates/skills/core/webcrawler/SKILL.md +292 -0
  71. package/templates/skills/core/webcrawler/references/advanced_crawling.md +181 -0
  72. package/templates/skills/core/webcrawler/scripts/crawl_docs.py +532 -0
  73. package/templates/skills/core/webcrawler/scripts/extract_page.py +189 -0
  74. package/templates/skills/core/webcrawler/scripts/filter_docs.py +200 -0
  75. package/templates/skills/knowledge/api-patterns/SKILL.md +81 -0
  76. package/templates/skills/knowledge/api-patterns/api-style.md +42 -0
  77. package/templates/skills/knowledge/api-patterns/auth.md +24 -0
  78. package/templates/skills/knowledge/api-patterns/documentation.md +26 -0
  79. package/templates/skills/knowledge/api-patterns/graphql.md +41 -0
  80. package/templates/skills/knowledge/api-patterns/rate-limiting.md +31 -0
  81. package/templates/skills/knowledge/api-patterns/response.md +37 -0
  82. package/templates/skills/knowledge/api-patterns/rest.md +40 -0
  83. package/templates/skills/knowledge/api-patterns/scripts/api_validator.py +211 -0
  84. package/templates/skills/knowledge/api-patterns/security-testing.md +122 -0
  85. package/templates/skills/knowledge/api-patterns/trpc.md +41 -0
  86. package/templates/skills/knowledge/api-patterns/versioning.md +22 -0
  87. package/templates/skills/knowledge/app-builder/SKILL.md +75 -0
  88. package/templates/skills/knowledge/app-builder/agent-coordination.md +71 -0
  89. package/templates/skills/knowledge/app-builder/feature-building.md +53 -0
  90. package/templates/skills/knowledge/app-builder/project-detection.md +34 -0
  91. package/templates/skills/knowledge/app-builder/scaffolding.md +118 -0
  92. package/templates/skills/knowledge/app-builder/tech-stack.md +40 -0
  93. package/templates/skills/knowledge/app-builder/templates/SKILL.md +39 -0
  94. package/templates/skills/knowledge/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  95. package/templates/skills/knowledge/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  96. package/templates/skills/knowledge/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  97. package/templates/skills/knowledge/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  98. package/templates/skills/knowledge/app-builder/templates/express-api/TEMPLATE.md +83 -0
  99. package/templates/skills/knowledge/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  100. package/templates/skills/knowledge/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  101. package/templates/skills/knowledge/app-builder/templates/nextjs-fullstack/TEMPLATE.md +82 -0
  102. package/templates/skills/knowledge/app-builder/templates/nextjs-saas/TEMPLATE.md +100 -0
  103. package/templates/skills/knowledge/app-builder/templates/nextjs-static/TEMPLATE.md +106 -0
  104. package/templates/skills/knowledge/app-builder/templates/nuxt-app/TEMPLATE.md +101 -0
  105. package/templates/skills/knowledge/app-builder/templates/python-fastapi/TEMPLATE.md +83 -0
  106. package/templates/skills/knowledge/app-builder/templates/react-native-app/TEMPLATE.md +93 -0
  107. package/templates/skills/knowledge/architecture/SKILL.md +55 -0
  108. package/templates/skills/knowledge/architecture/context-discovery.md +43 -0
  109. package/templates/skills/knowledge/architecture/examples.md +94 -0
  110. package/templates/skills/knowledge/architecture/pattern-selection.md +68 -0
  111. package/templates/skills/knowledge/architecture/patterns-reference.md +50 -0
  112. package/templates/skills/knowledge/architecture/trade-off-analysis.md +77 -0
  113. package/templates/skills/knowledge/bash-linux/SKILL.md +199 -0
  114. package/templates/skills/knowledge/behavioral-modes/SKILL.md +242 -0
  115. package/templates/skills/knowledge/brainstorming/SKILL.md +163 -0
  116. package/templates/skills/knowledge/brainstorming/dynamic-questioning.md +350 -0
  117. package/templates/skills/knowledge/clean-code/SKILL.md +201 -0
  118. package/templates/skills/knowledge/code-review-checklist/SKILL.md +109 -0
  119. package/templates/skills/knowledge/database-design/SKILL.md +52 -0
  120. package/templates/skills/knowledge/database-design/database-selection.md +43 -0
  121. package/templates/skills/knowledge/database-design/indexing.md +39 -0
  122. package/templates/skills/knowledge/database-design/migrations.md +48 -0
  123. package/templates/skills/knowledge/database-design/optimization.md +36 -0
  124. package/templates/skills/knowledge/database-design/orm-selection.md +30 -0
  125. package/templates/skills/knowledge/database-design/schema-design.md +56 -0
  126. package/templates/skills/knowledge/database-design/scripts/schema_validator.py +172 -0
  127. package/templates/skills/knowledge/deployment-procedures/SKILL.md +241 -0
  128. package/templates/skills/knowledge/doc.md +177 -0
  129. package/templates/skills/knowledge/documentation-templates/SKILL.md +194 -0
  130. package/templates/skills/knowledge/frontend-design/SKILL.md +396 -0
  131. package/templates/skills/knowledge/frontend-design/animation-guide.md +331 -0
  132. package/templates/skills/knowledge/frontend-design/color-system.md +311 -0
  133. package/templates/skills/knowledge/frontend-design/decision-trees.md +418 -0
  134. package/templates/skills/knowledge/frontend-design/motion-graphics.md +306 -0
  135. package/templates/skills/knowledge/frontend-design/scripts/accessibility_checker.py +183 -0
  136. package/templates/skills/knowledge/frontend-design/scripts/ux_audit.py +722 -0
  137. package/templates/skills/knowledge/frontend-design/typography-system.md +345 -0
  138. package/templates/skills/knowledge/frontend-design/ux-psychology.md +541 -0
  139. package/templates/skills/knowledge/frontend-design/visual-effects.md +383 -0
  140. package/templates/skills/knowledge/game-development/2d-games/SKILL.md +119 -0
  141. package/templates/skills/knowledge/game-development/3d-games/SKILL.md +135 -0
  142. package/templates/skills/knowledge/game-development/SKILL.md +167 -0
  143. package/templates/skills/knowledge/game-development/game-art/SKILL.md +185 -0
  144. package/templates/skills/knowledge/game-development/game-audio/SKILL.md +190 -0
  145. package/templates/skills/knowledge/game-development/game-design/SKILL.md +129 -0
  146. package/templates/skills/knowledge/game-development/mobile-games/SKILL.md +108 -0
  147. package/templates/skills/knowledge/game-development/multiplayer/SKILL.md +132 -0
  148. package/templates/skills/knowledge/game-development/pc-games/SKILL.md +144 -0
  149. package/templates/skills/knowledge/game-development/vr-ar/SKILL.md +123 -0
  150. package/templates/skills/knowledge/game-development/web-games/SKILL.md +150 -0
  151. package/templates/skills/knowledge/geo-fundamentals/SKILL.md +156 -0
  152. package/templates/skills/knowledge/geo-fundamentals/scripts/geo_checker.py +289 -0
  153. package/templates/skills/knowledge/i18n-localization/SKILL.md +154 -0
  154. package/templates/skills/knowledge/i18n-localization/scripts/i18n_checker.py +241 -0
  155. package/templates/skills/knowledge/intelligent-routing/SKILL.md +334 -0
  156. package/templates/skills/knowledge/lint-and-validate/SKILL.md +45 -0
  157. package/templates/skills/knowledge/lint-and-validate/scripts/lint_runner.py +172 -0
  158. package/templates/skills/knowledge/lint-and-validate/scripts/type_coverage.py +173 -0
  159. package/templates/skills/knowledge/mcp-builder/SKILL.md +176 -0
  160. package/templates/skills/knowledge/mobile-design/SKILL.md +394 -0
  161. package/templates/skills/knowledge/mobile-design/decision-trees.md +516 -0
  162. package/templates/skills/knowledge/mobile-design/mobile-backend.md +491 -0
  163. package/templates/skills/knowledge/mobile-design/mobile-color-system.md +420 -0
  164. package/templates/skills/knowledge/mobile-design/mobile-debugging.md +122 -0
  165. package/templates/skills/knowledge/mobile-design/mobile-design-thinking.md +357 -0
  166. package/templates/skills/knowledge/mobile-design/mobile-navigation.md +458 -0
  167. package/templates/skills/knowledge/mobile-design/mobile-performance.md +767 -0
  168. package/templates/skills/knowledge/mobile-design/mobile-testing.md +356 -0
  169. package/templates/skills/knowledge/mobile-design/mobile-typography.md +433 -0
  170. package/templates/skills/knowledge/mobile-design/platform-android.md +666 -0
  171. package/templates/skills/knowledge/mobile-design/platform-ios.md +561 -0
  172. package/templates/skills/knowledge/mobile-design/scripts/mobile_audit.py +670 -0
  173. package/templates/skills/knowledge/mobile-design/touch-psychology.md +537 -0
  174. package/templates/skills/knowledge/nextjs-best-practices/SKILL.md +203 -0
  175. package/templates/skills/knowledge/nodejs-best-practices/SKILL.md +333 -0
  176. package/templates/skills/knowledge/parallel-agents/SKILL.md +175 -0
  177. package/templates/skills/knowledge/performance-profiling/SKILL.md +143 -0
  178. package/templates/skills/knowledge/performance-profiling/scripts/lighthouse_audit.py +76 -0
  179. package/templates/skills/knowledge/plan-writing/SKILL.md +152 -0
  180. package/templates/skills/knowledge/powershell-windows/SKILL.md +167 -0
  181. package/templates/skills/knowledge/python-patterns/SKILL.md +441 -0
  182. package/templates/skills/knowledge/react-patterns/SKILL.md +198 -0
  183. package/templates/skills/knowledge/red-team-tactics/SKILL.md +199 -0
  184. package/templates/skills/knowledge/seo-fundamentals/SKILL.md +129 -0
  185. package/templates/skills/knowledge/seo-fundamentals/scripts/seo_checker.py +219 -0
  186. package/templates/skills/knowledge/server-management/SKILL.md +161 -0
  187. package/templates/skills/knowledge/systematic-debugging/SKILL.md +109 -0
  188. package/templates/skills/knowledge/tailwind-patterns/SKILL.md +269 -0
  189. package/templates/skills/knowledge/tdd-workflow/SKILL.md +149 -0
  190. package/templates/skills/knowledge/testing-patterns/SKILL.md +178 -0
  191. package/templates/skills/knowledge/testing-patterns/scripts/test_runner.py +219 -0
  192. package/templates/skills/knowledge/vulnerability-scanner/SKILL.md +276 -0
  193. package/templates/skills/knowledge/vulnerability-scanner/checklists.md +121 -0
  194. package/templates/skills/knowledge/vulnerability-scanner/scripts/security_scan.py +458 -0
  195. package/templates/skills/knowledge/webapp-testing/SKILL.md +187 -0
  196. package/templates/skills/knowledge/webapp-testing/scripts/playwright_runner.py +173 -0
@@ -0,0 +1,312 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Changelog Generator
4
+
5
+ Creates structured changelog entries from detected code changes.
6
+ Follows the Keep a Changelog format (https://keepachangelog.com/).
7
+
8
+ Usage:
9
+ python generate_changelog.py --scope <path> --since <commit|date> [options]
10
+
11
+ Arguments:
12
+ --scope Directory to analyze (required)
13
+ --since Changes since commit/date (required)
14
+ --output Output file (default: stdout)
15
+ --format Changelog format (default: keep-a-changelog)
16
+ --prepend Prepend to existing changelog (optional)
17
+
18
+ Exit Codes:
19
+ 0 - Success
20
+ 1 - Invalid arguments
21
+ 2 - Directory not found
22
+ 3 - Output error
23
+ """
24
+
25
+ import argparse
26
+ import json
27
+ import re
28
+ import subprocess
29
+ import sys
30
+ from datetime import datetime
31
+ from pathlib import Path
32
+ from typing import Dict, List, Optional, Tuple
33
+
34
+
35
+ def run_git_command(args: List[str], cwd: Path) -> Tuple[bool, str]:
36
+ """Execute a git command and return (success, output)."""
37
+ try:
38
+ result = subprocess.run(
39
+ ['git'] + args,
40
+ cwd=cwd,
41
+ capture_output=True,
42
+ text=True,
43
+ timeout=30
44
+ )
45
+ return result.returncode == 0, result.stdout.strip()
46
+ except Exception as e:
47
+ return False, str(e)
48
+
49
+
50
+ def get_git_log(scope: Path, since: str) -> List[Dict]:
51
+ """Get git log entries since a specific commit or date."""
52
+ # Format: hash|author|date|subject
53
+ success, output = run_git_command(
54
+ ['log', '--format=%H|%an|%ai|%s', since + '..HEAD', '--', str(scope)],
55
+ scope
56
+ )
57
+
58
+ if not success:
59
+ # Try alternative format
60
+ success, output = run_git_command(
61
+ ['log', '--format=%H|%an|%ai|%s', '-20', '--', str(scope)],
62
+ scope
63
+ )
64
+
65
+ if not success or not output:
66
+ return []
67
+
68
+ commits = []
69
+ for line in output.split('\n'):
70
+ if not line.strip():
71
+ continue
72
+
73
+ parts = line.split('|', 3)
74
+ if len(parts) >= 4:
75
+ commits.append({
76
+ 'hash': parts[0][:7],
77
+ 'author': parts[1],
78
+ 'date': parts[2].split()[0],
79
+ 'subject': parts[3]
80
+ })
81
+
82
+ return commits
83
+
84
+
85
+ def get_changed_files(scope: Path, since: str) -> Dict[str, List[str]]:
86
+ """Get files changed with their status."""
87
+ success, output = run_git_command(
88
+ ['diff', '--name-status', since, '--', str(scope)],
89
+ scope
90
+ )
91
+
92
+ if not success:
93
+ success, output = run_git_command(
94
+ ['diff', '--name-status', 'HEAD~10', '--', str(scope)],
95
+ scope
96
+ )
97
+
98
+ changes = {'added': [], 'modified': [], 'deleted': []}
99
+
100
+ if not success or not output:
101
+ return changes
102
+
103
+ for line in output.split('\n'):
104
+ if not line.strip():
105
+ continue
106
+
107
+ parts = line.split('\t')
108
+ if len(parts) < 2:
109
+ continue
110
+
111
+ status, filepath = parts[0], parts[1]
112
+
113
+ if status.startswith('A'):
114
+ changes['added'].append(filepath)
115
+ elif status.startswith('M'):
116
+ changes['modified'].append(filepath)
117
+ elif status.startswith('D'):
118
+ changes['deleted'].append(filepath)
119
+
120
+ return changes
121
+
122
+
123
+ def categorize_change(filepath: str) -> str:
124
+ """Categorize a file change for changelog purposes."""
125
+ if 'SKILL.md' in filepath:
126
+ return 'skill'
127
+ if '/scripts/' in filepath:
128
+ return 'script'
129
+ if '/references/' in filepath:
130
+ return 'documentation'
131
+ if filepath.endswith('.py'):
132
+ return 'code'
133
+ if filepath.endswith('.md'):
134
+ return 'documentation'
135
+ return 'other'
136
+
137
+
138
+ def generate_changelog_entry(changes: Dict, commits: List[Dict],
139
+ scope: str, version: str = 'Unreleased') -> str:
140
+ """Generate a changelog entry in Keep a Changelog format."""
141
+ today = datetime.now().strftime('%Y-%m-%d')
142
+
143
+ lines = [
144
+ f"## [{version}] - {today}",
145
+ ""
146
+ ]
147
+
148
+ # Group changes
149
+ added = []
150
+ changed = []
151
+ removed = []
152
+
153
+ for filepath in changes['added']:
154
+ category = categorize_change(filepath)
155
+ filename = Path(filepath).name
156
+
157
+ if category == 'skill':
158
+ added.append(f"New skill definition: `{Path(filepath).parent.name}`")
159
+ elif category == 'script':
160
+ skill = filepath.split('/scripts/')[0].split('/')[-1] if '/scripts/' in filepath else 'unknown'
161
+ added.append(f"New script `{filename}` for `{skill}` skill")
162
+ elif category == 'documentation':
163
+ added.append(f"New documentation: `{filename}`")
164
+ else:
165
+ added.append(f"Added `{filepath}`")
166
+
167
+ for filepath in changes['modified']:
168
+ category = categorize_change(filepath)
169
+ filename = Path(filepath).name
170
+
171
+ if category == 'skill':
172
+ skill = Path(filepath).parent.name
173
+ changed.append(f"Updated `{skill}` skill definition")
174
+ elif category == 'script':
175
+ skill = filepath.split('/scripts/')[0].split('/')[-1] if '/scripts/' in filepath else 'unknown'
176
+ changed.append(f"Modified `{filename}` in `{skill}` skill")
177
+ elif category == 'documentation':
178
+ changed.append(f"Updated documentation: `{filename}`")
179
+ else:
180
+ changed.append(f"Modified `{filepath}`")
181
+
182
+ for filepath in changes['deleted']:
183
+ category = categorize_change(filepath)
184
+ filename = Path(filepath).name
185
+
186
+ if category == 'skill':
187
+ removed.append(f"Removed skill: `{Path(filepath).parent.name}`")
188
+ else:
189
+ removed.append(f"Removed `{filepath}`")
190
+
191
+ # Deduplicate
192
+ added = list(dict.fromkeys(added))
193
+ changed = list(dict.fromkeys(changed))
194
+ removed = list(dict.fromkeys(removed))
195
+
196
+ # Write sections
197
+ if added:
198
+ lines.append("### Added")
199
+ for item in added:
200
+ lines.append(f"- {item}")
201
+ lines.append("")
202
+
203
+ if changed:
204
+ lines.append("### Changed")
205
+ for item in changed:
206
+ lines.append(f"- {item}")
207
+ lines.append("")
208
+
209
+ if removed:
210
+ lines.append("### Removed")
211
+ for item in removed:
212
+ lines.append(f"- {item}")
213
+ lines.append("")
214
+
215
+ # Add commit references if available
216
+ if commits:
217
+ lines.append("### Commits")
218
+ for commit in commits[:10]: # Limit to 10 commits
219
+ lines.append(f"- `{commit['hash']}` {commit['subject']}")
220
+ lines.append("")
221
+
222
+ return '\n'.join(lines)
223
+
224
+
225
+ def prepend_to_changelog(new_entry: str, changelog_path: Path) -> bool:
226
+ """Prepend a new entry to an existing changelog."""
227
+ if not changelog_path.exists():
228
+ # Create new changelog
229
+ header = """# Changelog
230
+
231
+ All notable changes to this project will be documented in this file.
232
+
233
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
234
+
235
+ """
236
+ changelog_path.write_text(header + new_entry)
237
+ return True
238
+
239
+ content = changelog_path.read_text()
240
+
241
+ # Find where to insert (after header, before first version)
242
+ insert_pattern = r'(# Changelog.*?\n\n)'
243
+ match = re.search(insert_pattern, content, re.DOTALL)
244
+
245
+ if match:
246
+ insert_pos = match.end()
247
+ new_content = content[:insert_pos] + new_entry + '\n' + content[insert_pos:]
248
+ changelog_path.write_text(new_content)
249
+ return True
250
+ else:
251
+ # Just prepend
252
+ changelog_path.write_text(new_entry + '\n' + content)
253
+ return True
254
+
255
+
256
+ def main():
257
+ parser = argparse.ArgumentParser(
258
+ description='Generate changelog entries from code changes',
259
+ formatter_class=argparse.RawDescriptionHelpFormatter,
260
+ epilog=__doc__
261
+ )
262
+ parser.add_argument('--scope', required=True, help='Directory to analyze')
263
+ parser.add_argument('--since', required=True, help='Changes since commit/date')
264
+ parser.add_argument('--output', help='Output file (default: stdout)')
265
+ parser.add_argument('--format', default='keep-a-changelog', help='Changelog format')
266
+ parser.add_argument('--prepend', action='store_true', help='Prepend to existing changelog')
267
+ parser.add_argument('--version', default='Unreleased', help='Version label')
268
+ args = parser.parse_args()
269
+
270
+ scope = Path(args.scope).resolve()
271
+
272
+ if not scope.exists():
273
+ print(f"❌ Error: Directory not found: {scope}", file=sys.stderr)
274
+ sys.exit(2)
275
+
276
+ print(f"📋 Generating changelog...", file=sys.stderr)
277
+ print(f" Scope: {scope}", file=sys.stderr)
278
+ print(f" Since: {args.since}", file=sys.stderr)
279
+
280
+ # Get changes and commits
281
+ changes = get_changed_files(scope, args.since)
282
+ commits = get_git_log(scope, args.since)
283
+
284
+ total_changes = sum(len(v) for v in changes.values())
285
+ print(f" Found {total_changes} changed file(s), {len(commits)} commit(s)", file=sys.stderr)
286
+
287
+ if total_changes == 0 and len(commits) == 0:
288
+ print(" No changes to document", file=sys.stderr)
289
+ sys.exit(0)
290
+
291
+ # Generate entry
292
+ entry = generate_changelog_entry(changes, commits, str(scope), args.version)
293
+
294
+ # Output
295
+ if args.output:
296
+ output_path = Path(args.output)
297
+
298
+ if args.prepend:
299
+ prepend_to_changelog(entry, output_path)
300
+ print(f"✅ Prepended to: {args.output}", file=sys.stderr)
301
+ else:
302
+ output_path.parent.mkdir(parents=True, exist_ok=True)
303
+ output_path.write_text(entry)
304
+ print(f"✅ Saved to: {args.output}", file=sys.stderr)
305
+ else:
306
+ print(entry)
307
+
308
+ sys.exit(0)
309
+
310
+
311
+ if __name__ == '__main__':
312
+ main()
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Full Documentation Synchronization
4
+
5
+ Orchestrates a complete documentation update across the entire repository.
6
+ Combines change detection, skill updates, and catalog synchronization.
7
+
8
+ Usage:
9
+ python sync_docs.py --skills-dir <path> [options]
10
+
11
+ Arguments:
12
+ --skills-dir Skills directory (required)
13
+ --update-catalog Update SKILLS_CATALOG.md (default: true)
14
+ --update-readme Update README.md if exists (optional)
15
+ --dry-run Preview changes without writing (optional)
16
+ --report Save sync report to file (optional)
17
+
18
+ Exit Codes:
19
+ 0 - Success
20
+ 1 - Invalid arguments
21
+ 2 - Directory not found
22
+ 3 - Sync error
23
+ """
24
+
25
+ import argparse
26
+ import subprocess
27
+ import sys
28
+ from datetime import datetime
29
+ from pathlib import Path
30
+ from typing import List, Dict, Tuple
31
+
32
+
33
+ def find_repo_root(start_path: Path) -> Path:
34
+ """Find repository root by looking for AGENTS.md or .git."""
35
+ current = start_path.resolve()
36
+
37
+ while current != current.parent:
38
+ if (current / 'AGENTS.md').exists() or (current / '.git').exists():
39
+ return current
40
+ current = current.parent
41
+
42
+ return start_path.resolve()
43
+
44
+
45
+ def scan_all_skills(skills_dir: Path) -> List[Dict]:
46
+ """Scan all skills and gather their metadata."""
47
+ skills = []
48
+
49
+ for item in sorted(skills_dir.iterdir()):
50
+ if not item.is_dir():
51
+ continue
52
+
53
+ skill_md = item / 'SKILL.md'
54
+ if not skill_md.exists():
55
+ continue
56
+
57
+ skill_info = {
58
+ 'name': item.name,
59
+ 'path': item,
60
+ 'scripts': list((item / 'scripts').glob('*.py')) if (item / 'scripts').exists() else [],
61
+ 'references': list((item / 'references').glob('*.md')) if (item / 'references').exists() else [],
62
+ 'has_assets': (item / 'assets').exists() and any((item / 'assets').iterdir()),
63
+ }
64
+
65
+ # Filter out example files
66
+ skill_info['scripts'] = [s for s in skill_info['scripts']
67
+ if not s.name.startswith('example') and not s.name.startswith('__')]
68
+ skill_info['references'] = [r for r in skill_info['references']
69
+ if not r.name.startswith('example')]
70
+
71
+ skills.append(skill_info)
72
+
73
+ return skills
74
+
75
+
76
+ def update_skill_timestamps(skills: List[Dict], dry_run: bool = False) -> List[Tuple[str, bool]]:
77
+ """Update the 'Last Updated' timestamp in all SKILL.md files."""
78
+ results = []
79
+ today = datetime.now().strftime('%Y-%m-%d')
80
+
81
+ for skill in skills:
82
+ skill_md = skill['path'] / 'SKILL.md'
83
+
84
+ try:
85
+ content = skill_md.read_text()
86
+
87
+ # Check if timestamp exists and update it
88
+ import re
89
+ pattern = r'>\s*\*\*Last Updated:\*\*\s*\d{4}-\d{2}-\d{2}'
90
+ replacement = f'> **Last Updated:** {today}'
91
+
92
+ if re.search(pattern, content):
93
+ new_content = re.sub(pattern, replacement, content)
94
+
95
+ if new_content != content and not dry_run:
96
+ skill_md.write_text(new_content)
97
+ results.append((skill['name'], True))
98
+ else:
99
+ results.append((skill['name'], False)) # No change needed or dry run
100
+ else:
101
+ results.append((skill['name'], False)) # No timestamp found
102
+
103
+ except Exception as e:
104
+ print(f" ⚠️ Error updating {skill['name']}: {e}", file=sys.stderr)
105
+ results.append((skill['name'], False))
106
+
107
+ return results
108
+
109
+
110
+ def run_catalog_update(skills_dir: Path, repo_root: Path, dry_run: bool = False) -> bool:
111
+ """Run the skills catalog updater."""
112
+ update_script = repo_root / 'skill-creator' / 'scripts' / 'update_catalog.py'
113
+
114
+ if not update_script.exists():
115
+ print(f" ⚠️ Catalog update script not found: {update_script}", file=sys.stderr)
116
+ return False
117
+
118
+ if dry_run:
119
+ print(" 🔍 [Dry Run] Would update SKILLS_CATALOG.md")
120
+ return True
121
+
122
+ try:
123
+ result = subprocess.run(
124
+ [sys.executable, str(update_script), '--skills-dir', str(skills_dir)],
125
+ cwd=repo_root,
126
+ capture_output=True,
127
+ text=True,
128
+ timeout=60
129
+ )
130
+
131
+ if result.returncode == 0:
132
+ return True
133
+ else:
134
+ print(f" ⚠️ Catalog update failed: {result.stderr}", file=sys.stderr)
135
+ return False
136
+
137
+ except Exception as e:
138
+ print(f" ⚠️ Error running catalog update: {e}", file=sys.stderr)
139
+ return False
140
+
141
+
142
+ def generate_sync_report(skills: List[Dict], catalog_updated: bool,
143
+ timestamp_results: List[Tuple[str, bool]]) -> str:
144
+ """Generate a synchronization report."""
145
+ now = datetime.now().strftime('%Y-%m-%d %H:%M')
146
+
147
+ lines = [
148
+ "# Documentation Synchronization Report",
149
+ "",
150
+ f"> **Generated:** {now}",
151
+ "",
152
+ "---",
153
+ "",
154
+ "## Summary",
155
+ "",
156
+ f"- **Skills Scanned:** {len(skills)}",
157
+ f"- **Catalog Updated:** {'✅ Yes' if catalog_updated else '❌ No'}",
158
+ f"- **Timestamps Updated:** {sum(1 for _, updated in timestamp_results if updated)}",
159
+ "",
160
+ "---",
161
+ "",
162
+ "## Skills Overview",
163
+ "",
164
+ "| Skill | Scripts | References | Timestamp Updated |",
165
+ "|-------|---------|------------|-------------------|",
166
+ ]
167
+
168
+ for skill in skills:
169
+ name = skill['name']
170
+ scripts_count = len(skill['scripts'])
171
+ refs_count = len(skill['references'])
172
+
173
+ # Find timestamp result
174
+ ts_updated = '—'
175
+ for ts_name, updated in timestamp_results:
176
+ if ts_name == name:
177
+ ts_updated = '✅' if updated else '—'
178
+ break
179
+
180
+ lines.append(f"| `{name}` | {scripts_count} | {refs_count} | {ts_updated} |")
181
+
182
+ lines.extend([
183
+ "",
184
+ "---",
185
+ "",
186
+ "## Next Steps",
187
+ "",
188
+ ])
189
+
190
+ if not catalog_updated:
191
+ lines.append("- [ ] Manually run catalog update if it failed")
192
+
193
+ lines.extend([
194
+ "- [ ] Review any skills with warnings",
195
+ "- [ ] Commit documentation changes",
196
+ "",
197
+ ])
198
+
199
+ return '\n'.join(lines)
200
+
201
+
202
+ def main():
203
+ parser = argparse.ArgumentParser(
204
+ description='Synchronize all documentation',
205
+ formatter_class=argparse.RawDescriptionHelpFormatter,
206
+ epilog=__doc__
207
+ )
208
+ parser.add_argument('--skills-dir', required=True, help='Skills directory')
209
+ parser.add_argument('--update-catalog', type=bool, default=True, help='Update catalog')
210
+ parser.add_argument('--update-readme', action='store_true', help='Update README.md')
211
+ parser.add_argument('--dry-run', action='store_true', help='Preview without writing')
212
+ parser.add_argument('--report', help='Save report to file')
213
+ args = parser.parse_args()
214
+
215
+ skills_dir = Path(args.skills_dir).resolve()
216
+
217
+ if not skills_dir.exists():
218
+ print(f"❌ Error: Skills directory not found: {skills_dir}", file=sys.stderr)
219
+ sys.exit(2)
220
+
221
+ repo_root = find_repo_root(skills_dir)
222
+
223
+ print(f"🔄 Documentation Synchronization")
224
+ print(f" Skills directory: {skills_dir}")
225
+ print(f" Repository root: {repo_root}")
226
+ if args.dry_run:
227
+ print(f" Mode: DRY RUN (no changes will be written)")
228
+ print()
229
+
230
+ # Scan all skills
231
+ print("📂 Scanning skills...")
232
+ skills = scan_all_skills(skills_dir)
233
+ print(f" Found {len(skills)} skill(s)")
234
+
235
+ # Update timestamps
236
+ print("\n📅 Updating timestamps...")
237
+ timestamp_results = update_skill_timestamps(skills, args.dry_run)
238
+ updated_count = sum(1 for _, updated in timestamp_results if updated)
239
+ print(f" Updated {updated_count} timestamp(s)")
240
+
241
+ # Update catalog
242
+ catalog_updated = False
243
+ if args.update_catalog:
244
+ print("\n📚 Updating skills catalog...")
245
+ catalog_updated = run_catalog_update(skills_dir, repo_root, args.dry_run)
246
+ if catalog_updated:
247
+ print(" ✅ Catalog updated successfully")
248
+ else:
249
+ print(" ⚠️ Catalog update had issues")
250
+
251
+ # Generate report
252
+ report = generate_sync_report(skills, catalog_updated, timestamp_results)
253
+
254
+ if args.report:
255
+ report_path = Path(args.report)
256
+ report_path.parent.mkdir(parents=True, exist_ok=True)
257
+
258
+ if not args.dry_run:
259
+ report_path.write_text(report)
260
+ print(f"\n📋 Report saved to: {args.report}")
261
+ else:
262
+ print(f"\n📋 [Dry Run] Would save report to: {args.report}")
263
+
264
+ print("\n" + "=" * 50)
265
+ print("✅ Documentation synchronization complete!")
266
+ print("=" * 50)
267
+
268
+ sys.exit(0)
269
+
270
+
271
+ if __name__ == '__main__':
272
+ main()