wogiflow 1.0.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 (221) hide show
  1. package/.workflow/agents/reviewer.md +81 -0
  2. package/.workflow/agents/security.md +94 -0
  3. package/.workflow/agents/story-writer.md +58 -0
  4. package/.workflow/bridges/base-bridge.js +395 -0
  5. package/.workflow/bridges/claude-bridge.js +434 -0
  6. package/.workflow/bridges/index.js +130 -0
  7. package/.workflow/lib/assumption-detector.js +481 -0
  8. package/.workflow/lib/config-substitution.js +371 -0
  9. package/.workflow/lib/failure-categories.js +478 -0
  10. package/.workflow/state/app-map.md.template +15 -0
  11. package/.workflow/state/architecture.md.template +24 -0
  12. package/.workflow/state/component-index.json.template +5 -0
  13. package/.workflow/state/decisions.md.template +15 -0
  14. package/.workflow/state/feedback-patterns.md.template +9 -0
  15. package/.workflow/state/knowledge-sync.json.template +6 -0
  16. package/.workflow/state/progress.md.template +14 -0
  17. package/.workflow/state/ready.json.template +7 -0
  18. package/.workflow/state/request-log.md.template +14 -0
  19. package/.workflow/state/session-state.json.template +11 -0
  20. package/.workflow/state/stack.md.template +33 -0
  21. package/.workflow/state/testing.md.template +36 -0
  22. package/.workflow/templates/claude-md.hbs +257 -0
  23. package/.workflow/templates/correction-report.md +67 -0
  24. package/.workflow/templates/gemini-md.hbs +52 -0
  25. package/README.md +1802 -0
  26. package/bin/flow +205 -0
  27. package/lib/index.js +33 -0
  28. package/lib/installer.js +467 -0
  29. package/lib/release-channel.js +269 -0
  30. package/lib/skill-registry.js +526 -0
  31. package/lib/upgrader.js +401 -0
  32. package/lib/utils.js +305 -0
  33. package/package.json +64 -0
  34. package/scripts/flow +985 -0
  35. package/scripts/flow-adaptive-learning.js +1259 -0
  36. package/scripts/flow-aggregate.js +488 -0
  37. package/scripts/flow-archive +133 -0
  38. package/scripts/flow-auto-context.js +1015 -0
  39. package/scripts/flow-auto-learn.js +615 -0
  40. package/scripts/flow-bridge.js +223 -0
  41. package/scripts/flow-browser-suggest.js +316 -0
  42. package/scripts/flow-bug.js +247 -0
  43. package/scripts/flow-cascade.js +711 -0
  44. package/scripts/flow-changelog +85 -0
  45. package/scripts/flow-checkpoint.js +483 -0
  46. package/scripts/flow-cli.js +403 -0
  47. package/scripts/flow-code-intelligence.js +760 -0
  48. package/scripts/flow-complexity.js +502 -0
  49. package/scripts/flow-config-set.js +152 -0
  50. package/scripts/flow-constants.js +157 -0
  51. package/scripts/flow-context +152 -0
  52. package/scripts/flow-context-init.js +482 -0
  53. package/scripts/flow-context-monitor.js +384 -0
  54. package/scripts/flow-context-scoring.js +886 -0
  55. package/scripts/flow-correct.js +458 -0
  56. package/scripts/flow-damage-control.js +985 -0
  57. package/scripts/flow-deps +101 -0
  58. package/scripts/flow-diff.js +700 -0
  59. package/scripts/flow-done +151 -0
  60. package/scripts/flow-done.js +489 -0
  61. package/scripts/flow-durable-session.js +1541 -0
  62. package/scripts/flow-entropy-monitor.js +345 -0
  63. package/scripts/flow-export-profile +349 -0
  64. package/scripts/flow-export-scanner.js +1046 -0
  65. package/scripts/flow-figma-confirm.js +400 -0
  66. package/scripts/flow-figma-extract.js +496 -0
  67. package/scripts/flow-figma-generate.js +683 -0
  68. package/scripts/flow-figma-index.js +909 -0
  69. package/scripts/flow-figma-match.js +617 -0
  70. package/scripts/flow-figma-mcp-server.js +518 -0
  71. package/scripts/flow-figma-pipeline.js +414 -0
  72. package/scripts/flow-file-ops.js +301 -0
  73. package/scripts/flow-gate-confidence.js +825 -0
  74. package/scripts/flow-guided-edit.js +659 -0
  75. package/scripts/flow-health +185 -0
  76. package/scripts/flow-health.js +413 -0
  77. package/scripts/flow-hooks.js +556 -0
  78. package/scripts/flow-http-client.js +249 -0
  79. package/scripts/flow-hybrid-detect.js +167 -0
  80. package/scripts/flow-hybrid-interactive.js +591 -0
  81. package/scripts/flow-hybrid-test.js +152 -0
  82. package/scripts/flow-import-profile +439 -0
  83. package/scripts/flow-init +253 -0
  84. package/scripts/flow-instruction-richness.js +827 -0
  85. package/scripts/flow-jira-integration.js +579 -0
  86. package/scripts/flow-knowledge-router.js +522 -0
  87. package/scripts/flow-knowledge-sync.js +589 -0
  88. package/scripts/flow-linear-integration.js +631 -0
  89. package/scripts/flow-links.js +774 -0
  90. package/scripts/flow-log-manager.js +559 -0
  91. package/scripts/flow-loop-enforcer.js +1246 -0
  92. package/scripts/flow-loop-retry-learning.js +630 -0
  93. package/scripts/flow-lsp.js +923 -0
  94. package/scripts/flow-map-index +348 -0
  95. package/scripts/flow-map-sync +201 -0
  96. package/scripts/flow-memory-blocks.js +668 -0
  97. package/scripts/flow-memory-compactor.js +350 -0
  98. package/scripts/flow-memory-db.js +1110 -0
  99. package/scripts/flow-memory-sync.js +484 -0
  100. package/scripts/flow-metrics.js +353 -0
  101. package/scripts/flow-migrate-ids.js +370 -0
  102. package/scripts/flow-model-adapter.js +802 -0
  103. package/scripts/flow-model-router.js +884 -0
  104. package/scripts/flow-models.js +1231 -0
  105. package/scripts/flow-morning.js +517 -0
  106. package/scripts/flow-multi-approach.js +660 -0
  107. package/scripts/flow-new-feature +86 -0
  108. package/scripts/flow-onboard +1042 -0
  109. package/scripts/flow-orchestrate-llm.js +459 -0
  110. package/scripts/flow-orchestrate.js +3592 -0
  111. package/scripts/flow-output.js +123 -0
  112. package/scripts/flow-parallel-detector.js +399 -0
  113. package/scripts/flow-parallel-dispatch.js +987 -0
  114. package/scripts/flow-parallel.js +428 -0
  115. package/scripts/flow-pattern-enforcer.js +600 -0
  116. package/scripts/flow-prd-manager.js +282 -0
  117. package/scripts/flow-progress.js +323 -0
  118. package/scripts/flow-project-analyzer.js +975 -0
  119. package/scripts/flow-prompt-composer.js +487 -0
  120. package/scripts/flow-providers.js +1381 -0
  121. package/scripts/flow-queue.js +308 -0
  122. package/scripts/flow-ready +82 -0
  123. package/scripts/flow-ready.js +189 -0
  124. package/scripts/flow-regression.js +396 -0
  125. package/scripts/flow-response-parser.js +450 -0
  126. package/scripts/flow-resume.js +284 -0
  127. package/scripts/flow-rules-sync.js +439 -0
  128. package/scripts/flow-run-trace.js +718 -0
  129. package/scripts/flow-safety.js +587 -0
  130. package/scripts/flow-search +104 -0
  131. package/scripts/flow-security.js +481 -0
  132. package/scripts/flow-session-end +106 -0
  133. package/scripts/flow-session-end.js +437 -0
  134. package/scripts/flow-session-state.js +671 -0
  135. package/scripts/flow-setup-hooks +216 -0
  136. package/scripts/flow-setup-hooks.js +377 -0
  137. package/scripts/flow-skill-create.js +329 -0
  138. package/scripts/flow-skill-creator.js +572 -0
  139. package/scripts/flow-skill-generator.js +1046 -0
  140. package/scripts/flow-skill-learn.js +880 -0
  141. package/scripts/flow-skill-matcher.js +578 -0
  142. package/scripts/flow-spec-generator.js +820 -0
  143. package/scripts/flow-stack-wizard.js +895 -0
  144. package/scripts/flow-standup +162 -0
  145. package/scripts/flow-start +74 -0
  146. package/scripts/flow-start.js +235 -0
  147. package/scripts/flow-status +110 -0
  148. package/scripts/flow-status.js +301 -0
  149. package/scripts/flow-step-browser.js +83 -0
  150. package/scripts/flow-step-changelog.js +217 -0
  151. package/scripts/flow-step-comments.js +306 -0
  152. package/scripts/flow-step-complexity.js +234 -0
  153. package/scripts/flow-step-coverage.js +218 -0
  154. package/scripts/flow-step-knowledge.js +193 -0
  155. package/scripts/flow-step-pr-tests.js +364 -0
  156. package/scripts/flow-step-regression.js +89 -0
  157. package/scripts/flow-step-review.js +516 -0
  158. package/scripts/flow-step-security.js +162 -0
  159. package/scripts/flow-step-silent-failures.js +290 -0
  160. package/scripts/flow-step-simplifier.js +346 -0
  161. package/scripts/flow-story +105 -0
  162. package/scripts/flow-story.js +500 -0
  163. package/scripts/flow-suspend.js +252 -0
  164. package/scripts/flow-sync-daemon.js +654 -0
  165. package/scripts/flow-task-analyzer.js +606 -0
  166. package/scripts/flow-team-dashboard.js +748 -0
  167. package/scripts/flow-team-sync.js +752 -0
  168. package/scripts/flow-team.js +977 -0
  169. package/scripts/flow-tech-options.js +528 -0
  170. package/scripts/flow-templates.js +812 -0
  171. package/scripts/flow-tiered-learning.js +728 -0
  172. package/scripts/flow-trace +204 -0
  173. package/scripts/flow-transcript-chunking.js +1106 -0
  174. package/scripts/flow-transcript-digest.js +7918 -0
  175. package/scripts/flow-transcript-language.js +465 -0
  176. package/scripts/flow-transcript-parsing.js +1085 -0
  177. package/scripts/flow-transcript-stories.js +2194 -0
  178. package/scripts/flow-update-map +224 -0
  179. package/scripts/flow-utils.js +2242 -0
  180. package/scripts/flow-verification.js +644 -0
  181. package/scripts/flow-verify.js +1177 -0
  182. package/scripts/flow-voice-input.js +638 -0
  183. package/scripts/flow-watch +168 -0
  184. package/scripts/flow-workflow-steps.js +521 -0
  185. package/scripts/flow-workflow.js +1029 -0
  186. package/scripts/flow-worktree.js +489 -0
  187. package/scripts/hooks/adapters/base-adapter.js +102 -0
  188. package/scripts/hooks/adapters/claude-code.js +359 -0
  189. package/scripts/hooks/adapters/index.js +79 -0
  190. package/scripts/hooks/core/component-check.js +341 -0
  191. package/scripts/hooks/core/index.js +35 -0
  192. package/scripts/hooks/core/loop-check.js +241 -0
  193. package/scripts/hooks/core/session-context.js +294 -0
  194. package/scripts/hooks/core/task-gate.js +177 -0
  195. package/scripts/hooks/core/validation.js +230 -0
  196. package/scripts/hooks/entry/claude-code/post-tool-use.js +65 -0
  197. package/scripts/hooks/entry/claude-code/pre-tool-use.js +89 -0
  198. package/scripts/hooks/entry/claude-code/session-end.js +87 -0
  199. package/scripts/hooks/entry/claude-code/session-start.js +46 -0
  200. package/scripts/hooks/entry/claude-code/stop.js +43 -0
  201. package/scripts/postinstall.js +139 -0
  202. package/templates/browser-test-flow.json +56 -0
  203. package/templates/bug-report.md +43 -0
  204. package/templates/component-detail.md +42 -0
  205. package/templates/component.stories.tsx +49 -0
  206. package/templates/context/constraints.md +83 -0
  207. package/templates/context/conventions.md +177 -0
  208. package/templates/context/stack.md +60 -0
  209. package/templates/correction-report.md +90 -0
  210. package/templates/feature-proposal.md +35 -0
  211. package/templates/hybrid/_base.md +254 -0
  212. package/templates/hybrid/_patterns.md +45 -0
  213. package/templates/hybrid/create-component.md +127 -0
  214. package/templates/hybrid/create-file.md +56 -0
  215. package/templates/hybrid/create-hook.md +145 -0
  216. package/templates/hybrid/create-service.md +70 -0
  217. package/templates/hybrid/fix-bug.md +33 -0
  218. package/templates/hybrid/modify-file.md +55 -0
  219. package/templates/story.md +68 -0
  220. package/templates/task.json +56 -0
  221. package/templates/trace.md +69 -0
@@ -0,0 +1,348 @@
1
+ #!/bin/bash
2
+
3
+ # Wogi Flow - Component Index Scanner
4
+ # Auto-generates component index from codebase
5
+
6
+ set -e
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
10
+ WORKFLOW_DIR="$PROJECT_ROOT/.workflow"
11
+ INDEX_FILE="$WORKFLOW_DIR/state/component-index.json"
12
+ CONFIG_FILE="$WORKFLOW_DIR/config.json"
13
+
14
+ # Colors
15
+ GREEN='\033[0;32m'
16
+ YELLOW='\033[1;33m'
17
+ CYAN='\033[0;36m'
18
+ RED='\033[0;31m'
19
+ BOLD='\033[1m'
20
+ DIM='\033[2m'
21
+ NC='\033[0m'
22
+
23
+ show_help() {
24
+ echo "Wogi Flow - Component Index"
25
+ echo ""
26
+ echo "Usage: flow map-index [command]"
27
+ echo ""
28
+ echo "Commands:"
29
+ echo " (none) Show index summary"
30
+ echo " scan Rescan and regenerate index"
31
+ echo " full Show full index details"
32
+ echo " json Output raw JSON"
33
+ echo ""
34
+ }
35
+
36
+ get_config_value() {
37
+ local key="$1"
38
+ local default="$2"
39
+ python3 -c "
40
+ import json
41
+ try:
42
+ with open('$CONFIG_FILE', 'r') as f:
43
+ config = json.load(f)
44
+ keys = '$key'.split('.')
45
+ val = config
46
+ for k in keys:
47
+ val = val.get(k, {})
48
+ print(val if val else '$default')
49
+ except:
50
+ print('$default')
51
+ " 2>/dev/null
52
+ }
53
+
54
+ scan_codebase() {
55
+ echo -e "${CYAN}Scanning codebase...${NC}"
56
+
57
+ # Get directories from config
58
+ local dirs=$(python3 -c "
59
+ import json
60
+ try:
61
+ with open('$CONFIG_FILE', 'r') as f:
62
+ config = json.load(f)
63
+ dirs = config.get('componentIndex', {}).get('directories', ['src/components', 'src/hooks', 'src/services'])
64
+ print(' '.join(dirs))
65
+ except:
66
+ print('src/components src/hooks src/services')
67
+ " 2>/dev/null)
68
+
69
+ local ignore_patterns=$(python3 -c "
70
+ import json
71
+ try:
72
+ with open('$CONFIG_FILE', 'r') as f:
73
+ config = json.load(f)
74
+ patterns = config.get('componentIndex', {}).get('ignore', ['*.test.*', '*.spec.*'])
75
+ print(' '.join(patterns))
76
+ except:
77
+ print('*.test.* *.spec.* *.stories.*')
78
+ " 2>/dev/null)
79
+
80
+ # Build find command excludes
81
+ local excludes=""
82
+ for pattern in $ignore_patterns; do
83
+ excludes="$excludes -not -name '$pattern'"
84
+ done
85
+
86
+ # Create Python script to scan and categorize
87
+ python3 << EOF
88
+ import os
89
+ import json
90
+ import re
91
+ from datetime import datetime
92
+ from pathlib import Path
93
+
94
+ PROJECT_ROOT = "$PROJECT_ROOT"
95
+ INDEX_FILE = "$INDEX_FILE"
96
+ DIRS = "$dirs".split()
97
+ IGNORE = "$ignore_patterns".split()
98
+
99
+ def should_ignore(filepath):
100
+ name = os.path.basename(filepath)
101
+ for pattern in IGNORE:
102
+ pattern = pattern.replace('*', '.*')
103
+ if re.match(pattern, name):
104
+ return True
105
+ return False
106
+
107
+ def get_exports(filepath):
108
+ """Extract export names from file"""
109
+ exports = []
110
+ try:
111
+ with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
112
+ content = f.read()
113
+
114
+ # Match various export patterns
115
+ patterns = [
116
+ r'export\s+(?:default\s+)?(?:function|class|const|let|var)\s+(\w+)',
117
+ r'export\s+{\s*([^}]+)\s*}',
118
+ r'export\s+default\s+(\w+)',
119
+ ]
120
+
121
+ for pattern in patterns:
122
+ matches = re.findall(pattern, content)
123
+ for match in matches:
124
+ if isinstance(match, str):
125
+ # Handle export { A, B, C }
126
+ for name in match.split(','):
127
+ name = name.strip().split(' as ')[0].strip()
128
+ if name and name not in exports:
129
+ exports.append(name)
130
+ except:
131
+ pass
132
+
133
+ return exports[:5] # Limit to 5 exports
134
+
135
+ def categorize(filepath, name):
136
+ """Determine category based on path and name"""
137
+ path_lower = filepath.lower()
138
+ name_lower = name.lower()
139
+
140
+ if '/components/' in path_lower or name_lower.endswith('.component'):
141
+ return 'components'
142
+ elif '/pages/' in path_lower or '/app/' in path_lower and '/api/' not in path_lower:
143
+ return 'pages'
144
+ elif name_lower.startswith('use') or '/hooks/' in path_lower:
145
+ return 'hooks'
146
+ elif '.service' in name_lower or '/services/' in path_lower:
147
+ return 'services'
148
+ elif '.module' in name_lower or '/modules/' in path_lower:
149
+ return 'modules'
150
+ elif '/utils/' in path_lower or '/lib/' in path_lower or '/helpers/' in path_lower:
151
+ return 'utils'
152
+ elif '/api/' in path_lower:
153
+ return 'api'
154
+ else:
155
+ return 'other'
156
+
157
+ def scan():
158
+ index = {
159
+ 'lastScan': datetime.now().isoformat(),
160
+ 'scanConfig': {
161
+ 'directories': DIRS,
162
+ 'ignore': IGNORE
163
+ },
164
+ 'components': [],
165
+ 'pages': [],
166
+ 'hooks': [],
167
+ 'services': [],
168
+ 'modules': [],
169
+ 'utils': [],
170
+ 'api': [],
171
+ 'other': []
172
+ }
173
+
174
+ extensions = {'.tsx', '.jsx', '.ts', '.js', '.vue'}
175
+
176
+ for scan_dir in DIRS:
177
+ full_dir = os.path.join(PROJECT_ROOT, scan_dir)
178
+ if not os.path.exists(full_dir):
179
+ continue
180
+
181
+ for root, dirs, files in os.walk(full_dir):
182
+ # Skip node_modules, __tests__, etc
183
+ dirs[:] = [d for d in dirs if not d.startswith('.') and d not in ['node_modules', '__tests__', '__mocks__', 'dist', 'build']]
184
+
185
+ for file in files:
186
+ filepath = os.path.join(root, file)
187
+ rel_path = os.path.relpath(filepath, PROJECT_ROOT)
188
+
189
+ # Check extension
190
+ ext = os.path.splitext(file)[1]
191
+ if ext not in extensions:
192
+ continue
193
+
194
+ # Check ignore patterns
195
+ if should_ignore(filepath):
196
+ continue
197
+
198
+ # Get name without extension
199
+ name = os.path.splitext(file)[0]
200
+ if name in ['index', 'types', 'constants', 'styles']:
201
+ # Use parent directory name
202
+ name = os.path.basename(os.path.dirname(filepath))
203
+
204
+ # Categorize
205
+ category = categorize(rel_path, name)
206
+
207
+ # Get exports
208
+ exports = get_exports(filepath)
209
+
210
+ entry = {
211
+ 'name': name,
212
+ 'path': rel_path,
213
+ 'exports': exports
214
+ }
215
+
216
+ index[category].append(entry)
217
+
218
+ # Sort each category
219
+ for cat in ['components', 'pages', 'hooks', 'services', 'modules', 'utils', 'api', 'other']:
220
+ index[cat] = sorted(index[cat], key=lambda x: x['name'].lower())
221
+
222
+ # Remove empty categories except core ones
223
+ if not index['other']:
224
+ del index['other']
225
+ if not index['api']:
226
+ del index['api']
227
+
228
+ # Save
229
+ with open(INDEX_FILE, 'w') as f:
230
+ json.dump(index, f, indent=2)
231
+
232
+ # Print summary
233
+ total = sum(len(index.get(cat, [])) for cat in ['components', 'pages', 'hooks', 'services', 'modules', 'utils'])
234
+ print(f"Scanned {len(DIRS)} directories")
235
+ print(f"Found {total} items")
236
+
237
+ return index
238
+
239
+ scan()
240
+ EOF
241
+
242
+ echo -e "${GREEN}āœ“${NC} Index updated"
243
+ }
244
+
245
+ show_summary() {
246
+ if [ ! -f "$INDEX_FILE" ]; then
247
+ echo -e "${YELLOW}No index found. Run: flow map-index scan${NC}"
248
+ exit 1
249
+ fi
250
+
251
+ python3 << EOF
252
+ import json
253
+ from datetime import datetime
254
+
255
+ with open('$INDEX_FILE', 'r') as f:
256
+ index = json.load(f)
257
+
258
+ last_scan = index.get('lastScan', 'Never')
259
+ if last_scan != 'Never':
260
+ try:
261
+ dt = datetime.fromisoformat(last_scan.replace('Z', '+00:00'))
262
+ last_scan = dt.strftime('%Y-%m-%d %H:%M')
263
+ except:
264
+ pass
265
+
266
+ print("\nšŸ“¦ Component Index")
267
+ print(f"\nLast scan: {last_scan}")
268
+ print()
269
+ print("| Category | Count |")
270
+ print("|------------|-------|")
271
+
272
+ total = 0
273
+ for cat in ['components', 'pages', 'hooks', 'services', 'modules', 'utils']:
274
+ count = len(index.get(cat, []))
275
+ total += count
276
+ if count > 0:
277
+ print(f"| {cat.capitalize():<10} | {count:>5} |")
278
+
279
+ print(f"\nTotal: {total} items")
280
+ print("\nRun: flow map-index full (for details)")
281
+ print("Run: flow map-index scan (to refresh)")
282
+ EOF
283
+ }
284
+
285
+ show_full() {
286
+ if [ ! -f "$INDEX_FILE" ]; then
287
+ echo -e "${YELLOW}No index found. Run: flow map-index scan${NC}"
288
+ exit 1
289
+ fi
290
+
291
+ python3 << EOF
292
+ import json
293
+
294
+ with open('$INDEX_FILE', 'r') as f:
295
+ index = json.load(f)
296
+
297
+ print("\nšŸ“¦ Component Index (Full)\n")
298
+
299
+ for cat in ['components', 'pages', 'hooks', 'services', 'modules', 'utils']:
300
+ items = index.get(cat, [])
301
+ if not items:
302
+ continue
303
+
304
+ print(f"## {cat.capitalize()} ({len(items)})\n")
305
+ print("| Name | Path | Exports |")
306
+ print("|------|------|---------|")
307
+
308
+ for item in items[:50]: # Limit display
309
+ name = item['name']
310
+ path = item['path']
311
+ exports = ', '.join(item.get('exports', [])[:3])
312
+ if len(item.get('exports', [])) > 3:
313
+ exports += '...'
314
+ print(f"| {name} | {path} | {exports} |")
315
+
316
+ if len(items) > 50:
317
+ print(f"\n... and {len(items) - 50} more\n")
318
+ print()
319
+ EOF
320
+ }
321
+
322
+ show_json() {
323
+ if [ ! -f "$INDEX_FILE" ]; then
324
+ echo "{}"
325
+ exit 1
326
+ fi
327
+ cat "$INDEX_FILE"
328
+ }
329
+
330
+ # Main
331
+ case "${1:-}" in
332
+ scan)
333
+ scan_codebase
334
+ show_summary
335
+ ;;
336
+ full)
337
+ show_full
338
+ ;;
339
+ json)
340
+ show_json
341
+ ;;
342
+ help|--help|-h)
343
+ show_help
344
+ ;;
345
+ *)
346
+ show_summary
347
+ ;;
348
+ esac
@@ -0,0 +1,201 @@
1
+ #!/bin/bash
2
+
3
+ # Wogi Flow - App Map Sync
4
+ # Compare auto-generated index with curated app-map
5
+
6
+ set -e
7
+
8
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
10
+ WORKFLOW_DIR="$PROJECT_ROOT/.workflow"
11
+ INDEX_FILE="$WORKFLOW_DIR/state/component-index.json"
12
+ APPMAP_FILE="$WORKFLOW_DIR/state/app-map.md"
13
+
14
+ # Colors
15
+ GREEN='\033[0;32m'
16
+ YELLOW='\033[1;33m'
17
+ CYAN='\033[0;36m'
18
+ RED='\033[0;31m'
19
+ BOLD='\033[1m'
20
+ DIM='\033[2m'
21
+ NC='\033[0m'
22
+
23
+ show_help() {
24
+ echo "Wogi Flow - App Map Sync"
25
+ echo ""
26
+ echo "Compare auto-generated index with curated app-map"
27
+ echo ""
28
+ echo "Usage: flow map-sync"
29
+ echo ""
30
+ echo "This will:"
31
+ echo " 1. Compare component-index.json with app-map.md"
32
+ echo " 2. Show items in codebase but not in app-map"
33
+ echo " 3. Show items in app-map but not in codebase (stale)"
34
+ echo " 4. Offer to update app-map"
35
+ echo ""
36
+ }
37
+
38
+ check_files() {
39
+ if [ ! -f "$INDEX_FILE" ]; then
40
+ echo -e "${YELLOW}No component index found.${NC}"
41
+ echo "Running scan first..."
42
+ "$SCRIPT_DIR/flow-map-index" scan
43
+ fi
44
+
45
+ if [ ! -f "$APPMAP_FILE" ]; then
46
+ echo -e "${RED}No app-map.md found at $APPMAP_FILE${NC}"
47
+ exit 1
48
+ fi
49
+ }
50
+
51
+ sync_maps() {
52
+ python3 << 'EOF'
53
+ import json
54
+ import re
55
+ import os
56
+ from datetime import datetime
57
+
58
+ INDEX_FILE = os.environ.get('INDEX_FILE', '.workflow/state/component-index.json')
59
+ APPMAP_FILE = os.environ.get('APPMAP_FILE', '.workflow/state/app-map.md')
60
+
61
+ # Load index
62
+ with open(INDEX_FILE, 'r') as f:
63
+ index = json.load(f)
64
+
65
+ # Load app-map and extract component names
66
+ with open(APPMAP_FILE, 'r') as f:
67
+ appmap_content = f.read()
68
+
69
+ # Extract names from app-map tables
70
+ # Pattern matches: | ComponentName | ... |
71
+ appmap_names = set()
72
+ appmap_paths = {}
73
+
74
+ table_pattern = r'\|\s*([A-Za-z][A-Za-z0-9_-]*)\s*\|'
75
+ path_pattern = r'\|\s*([A-Za-z][A-Za-z0-9_-]*)\s*\|[^|]*\|[^|]*\|\s*([^\s|]+)\s*\|'
76
+
77
+ for match in re.finditer(table_pattern, appmap_content):
78
+ name = match.group(1)
79
+ # Skip table headers
80
+ if name.lower() not in ['component', 'screen', 'name', 'hook', 'service', 'module', 'route', 'path', 'description', 'variants', 'type']:
81
+ appmap_names.add(name.lower())
82
+
83
+ # Also try to extract paths for stale detection
84
+ for match in re.finditer(path_pattern, appmap_content):
85
+ name = match.group(1).lower()
86
+ path = match.group(2)
87
+ if name not in ['component', 'screen', 'name', 'path']:
88
+ appmap_paths[name] = path
89
+
90
+ # Get all names from index
91
+ index_names = {}
92
+ for category in ['components', 'pages', 'hooks', 'services', 'modules', 'utils']:
93
+ for item in index.get(category, []):
94
+ name_lower = item['name'].lower()
95
+ index_names[name_lower] = {
96
+ 'name': item['name'],
97
+ 'path': item['path'],
98
+ 'category': category
99
+ }
100
+
101
+ # Find differences
102
+ in_code_not_map = []
103
+ in_map_not_code = []
104
+ in_sync = []
105
+
106
+ for name_lower, info in index_names.items():
107
+ if name_lower in appmap_names:
108
+ in_sync.append(info['name'])
109
+ else:
110
+ in_code_not_map.append(info)
111
+
112
+ for name_lower in appmap_names:
113
+ if name_lower not in index_names:
114
+ path = appmap_paths.get(name_lower, 'unknown path')
115
+ in_map_not_code.append({'name': name_lower, 'path': path})
116
+
117
+ # Output
118
+ last_scan = index.get('lastScan', 'unknown')
119
+ try:
120
+ dt = datetime.fromisoformat(last_scan.replace('Z', '+00:00'))
121
+ last_scan = dt.strftime('%Y-%m-%d')
122
+ except:
123
+ pass
124
+
125
+ print("\nšŸ”„ App Map Sync")
126
+ print()
127
+ print(f"Comparing component-index.json (scanned: {last_scan})")
128
+ print(f" with app-map.md")
129
+ print()
130
+ print("━" * 55)
131
+
132
+ if in_code_not_map:
133
+ print()
134
+ print("šŸ“„ IN CODEBASE, NOT IN APP-MAP (consider adding):")
135
+ print()
136
+
137
+ # Group by category
138
+ by_category = {}
139
+ for item in in_code_not_map:
140
+ cat = item['category']
141
+ if cat not in by_category:
142
+ by_category[cat] = []
143
+ by_category[cat].append(item)
144
+
145
+ for cat, items in sorted(by_category.items()):
146
+ print(f" {cat.capitalize()}:")
147
+ for item in items[:10]:
148
+ print(f" • {item['name']} ({item['path']})")
149
+ if len(items) > 10:
150
+ print(f" ... and {len(items) - 10} more")
151
+ print()
152
+
153
+ print("━" * 55)
154
+
155
+ if in_map_not_code:
156
+ print()
157
+ print("šŸ“¤ IN APP-MAP, NOT IN CODEBASE (possibly stale):")
158
+ print()
159
+ for item in in_map_not_code[:10]:
160
+ print(f" • {item['name']} (was at {item['path']})")
161
+ if len(in_map_not_code) > 10:
162
+ print(f" ... and {len(in_map_not_code) - 10} more")
163
+ print()
164
+ print("━" * 55)
165
+
166
+ print()
167
+ print(f"āœ… IN SYNC: {len(in_sync)} items match")
168
+ print()
169
+ print("━" * 55)
170
+ print()
171
+
172
+ # Summary
173
+ missing_count = len(in_code_not_map)
174
+ stale_count = len(in_map_not_code)
175
+
176
+ if missing_count == 0 and stale_count == 0:
177
+ print("šŸŽ‰ App map is fully in sync with codebase!")
178
+ else:
179
+ print("Suggestions:")
180
+ if missing_count > 0:
181
+ print(f" • Add {missing_count} missing items: /wogi-map-add")
182
+ if stale_count > 0:
183
+ print(f" • Review {stale_count} possibly stale entries")
184
+ print()
185
+ EOF
186
+ }
187
+
188
+ # Export paths for Python
189
+ export INDEX_FILE
190
+ export APPMAP_FILE
191
+
192
+ # Main
193
+ case "${1:-}" in
194
+ help|--help|-h)
195
+ show_help
196
+ ;;
197
+ *)
198
+ check_files
199
+ sync_maps
200
+ ;;
201
+ esac