claude-code-workflow 6.3.43 → 6.3.46

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 (78) hide show
  1. package/.claude/agents/tdd-developer.md +530 -0
  2. package/.claude/commands/ccw-coordinator.md +1042 -0
  3. package/.claude/commands/ccw.md +486 -0
  4. package/.claude/commands/issue/discover-by-prompt.md +5 -1
  5. package/.claude/commands/issue/discover.md +472 -468
  6. package/.claude/commands/issue/execute.md +580 -581
  7. package/.claude/commands/issue/new.md +417 -413
  8. package/.claude/commands/issue/plan.md +5 -1
  9. package/.claude/commands/issue/queue.md +445 -441
  10. package/.claude/commands/task/breakdown.md +207 -203
  11. package/.claude/commands/task/replan.md +440 -436
  12. package/.claude/commands/workflow/action-plan-verify.md +485 -447
  13. package/.claude/commands/workflow/brainstorm/artifacts.md +457 -453
  14. package/.claude/commands/workflow/brainstorm/auto-parallel.md +5 -1
  15. package/.claude/commands/workflow/brainstorm/synthesis.md +402 -398
  16. package/.claude/commands/workflow/clean.md +67 -35
  17. package/.claude/commands/workflow/debug-with-file.md +670 -666
  18. package/.claude/commands/workflow/debug.md +331 -327
  19. package/.claude/commands/workflow/develop-with-file.md +5 -1
  20. package/.claude/commands/workflow/execute.md +546 -498
  21. package/.claude/commands/workflow/lite-execute.md +44 -26
  22. package/.claude/commands/workflow/lite-fix.md +780 -730
  23. package/.claude/commands/workflow/lite-lite-lite.md +5 -1
  24. package/.claude/commands/workflow/lite-plan.md +87 -39
  25. package/.claude/commands/workflow/multi-cli-plan.md +572 -568
  26. package/.claude/commands/workflow/plan-verify.md +527 -0
  27. package/.claude/commands/workflow/plan.md +555 -551
  28. package/.claude/commands/workflow/replan.md +572 -515
  29. package/.claude/commands/workflow/review-fix.md +608 -610
  30. package/.claude/commands/workflow/session/complete.md +37 -14
  31. package/.claude/commands/workflow/session/solidify.md +303 -299
  32. package/.claude/commands/workflow/tdd-plan.md +630 -597
  33. package/.claude/commands/workflow/tdd-verify.md +391 -206
  34. package/.claude/commands/workflow/tools/conflict-resolution.md +24 -12
  35. package/.claude/commands/workflow/tools/task-generate-agent.md +583 -563
  36. package/.claude/commands/workflow/tools/task-generate-tdd.md +749 -517
  37. package/.claude/commands/workflow/ui-design/animation-extract.md +1154 -1150
  38. package/.claude/commands/workflow/ui-design/layout-extract.md +792 -788
  39. package/.claude/commands/workflow/ui-design/style-extract.md +777 -773
  40. package/.claude/skills/ccw-help/command.json +5 -5
  41. package/.claude/skills/ccw-help/scripts/analyze_commands.py +337 -337
  42. package/.claude/workflows/cli-templates/prompts/workflow-impl-plan-template.txt +1 -1
  43. package/ccw/dist/commands/issue.d.ts +4 -0
  44. package/ccw/dist/commands/issue.d.ts.map +1 -1
  45. package/ccw/dist/commands/issue.js +73 -6
  46. package/ccw/dist/commands/issue.js.map +1 -1
  47. package/ccw/dist/core/routes/cli-routes.d.ts.map +1 -1
  48. package/ccw/dist/core/routes/cli-routes.js +32 -28
  49. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  50. package/ccw/dist/tools/claude-cli-tools.d.ts +10 -0
  51. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
  52. package/ccw/dist/tools/claude-cli-tools.js +45 -0
  53. package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
  54. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  55. package/ccw/dist/tools/codex-lens.js +38 -11
  56. package/ccw/dist/tools/codex-lens.js.map +1 -1
  57. package/ccw/dist/tools/command-registry.d.ts +77 -0
  58. package/ccw/dist/tools/command-registry.d.ts.map +1 -0
  59. package/ccw/dist/tools/command-registry.js +265 -0
  60. package/ccw/dist/tools/command-registry.js.map +1 -0
  61. package/ccw/dist/tools/command-registry.test.d.ts +14 -0
  62. package/ccw/dist/tools/command-registry.test.d.ts.map +1 -0
  63. package/ccw/dist/tools/command-registry.test.js.map +1 -0
  64. package/ccw/dist/tools/index.d.ts +2 -0
  65. package/ccw/dist/tools/index.d.ts.map +1 -1
  66. package/ccw/dist/tools/index.js +2 -0
  67. package/ccw/dist/tools/index.js.map +1 -1
  68. package/ccw/src/commands/issue.ts +84 -6
  69. package/ccw/src/core/routes/cli-routes.ts +30 -25
  70. package/ccw/src/templates/dashboard-js/views/help.js +1 -1
  71. package/ccw/src/tools/claude-cli-tools.ts +50 -0
  72. package/ccw/src/tools/codex-lens.ts +40 -11
  73. package/ccw/src/tools/command-registry.test.ts +669 -0
  74. package/ccw/src/tools/command-registry.ts +308 -0
  75. package/ccw/src/tools/index.ts +4 -0
  76. package/package.json +1 -1
  77. package/.claude/skills/ccw/SKILL.md +0 -522
  78. package/.claude/skills/ccw/command.json +0 -641
@@ -1,337 +1,337 @@
1
- #!/usr/bin/env python3
2
- """
3
- Analyze all command/agent files and generate index files for ccw-help skill.
4
- Outputs relative paths pointing to source files (no reference folder duplication).
5
- """
6
-
7
- import os
8
- import re
9
- import json
10
- from pathlib import Path
11
- from collections import defaultdict
12
- from typing import Dict, List, Any
13
-
14
- # Base paths
15
- BASE_DIR = Path("D:/Claude_dms3/.claude")
16
- COMMANDS_DIR = BASE_DIR / "commands"
17
- AGENTS_DIR = BASE_DIR / "agents"
18
- SKILL_DIR = BASE_DIR / "skills" / "ccw-help"
19
- INDEX_DIR = SKILL_DIR / "index"
20
-
21
- def parse_frontmatter(content: str) -> Dict[str, Any]:
22
- """Extract YAML frontmatter from markdown content."""
23
- frontmatter = {}
24
- if content.startswith('---'):
25
- lines = content.split('\n')
26
- for i, line in enumerate(lines[1:], 1):
27
- if line.strip() == '---':
28
- break
29
- if ':' in line:
30
- key, value = line.split(':', 1)
31
- frontmatter[key.strip()] = value.strip().strip('"')
32
- return frontmatter
33
-
34
- def categorize_command(file_path: Path) -> tuple:
35
- """Determine category and subcategory from file path."""
36
- parts = file_path.relative_to(COMMANDS_DIR).parts
37
-
38
- if len(parts) == 1:
39
- return "general", None
40
-
41
- category = parts[0] # cli, memory, task, workflow
42
- subcategory = parts[1].replace('.md', '') if len(parts) > 2 else None
43
-
44
- return category, subcategory
45
-
46
- def determine_usage_scenario(name: str, description: str, category: str) -> str:
47
- """Determine primary usage scenario for command."""
48
- name_lower = name.lower()
49
-
50
- if any(word in name_lower for word in ['plan', 'design', 'breakdown', 'brainstorm']):
51
- return "planning"
52
- if any(word in name_lower for word in ['implement', 'execute', 'generate', 'create', 'write']):
53
- return "implementation"
54
- if any(word in name_lower for word in ['test', 'tdd', 'verify', 'coverage']):
55
- return "testing"
56
- if any(word in name_lower for word in ['docs', 'documentation', 'memory']):
57
- return "documentation"
58
- if any(word in name_lower for word in ['session', 'resume', 'status', 'complete']):
59
- return "session-management"
60
- if any(word in name_lower for word in ['analyze', 'review', 'diagnosis']):
61
- return "analysis"
62
- return "general"
63
-
64
- def determine_difficulty(name: str, description: str, category: str) -> str:
65
- """Determine difficulty level."""
66
- name_lower = name.lower()
67
-
68
- beginner_keywords = ['status', 'list', 'chat', 'analyze', 'version']
69
- if any(word in name_lower for word in beginner_keywords):
70
- return "Beginner"
71
-
72
- advanced_keywords = ['tdd', 'conflict', 'agent', 'auto-parallel', 'coverage', 'synthesis']
73
- if any(word in name_lower for word in advanced_keywords):
74
- return "Advanced"
75
-
76
- return "Intermediate"
77
-
78
- def analyze_command_file(file_path: Path) -> Dict[str, Any]:
79
- """Analyze a single command file and extract metadata."""
80
- with open(file_path, 'r', encoding='utf-8') as f:
81
- content = f.read()
82
-
83
- frontmatter = parse_frontmatter(content)
84
-
85
- name = frontmatter.get('name', file_path.stem)
86
- description = frontmatter.get('description', '')
87
- argument_hint = frontmatter.get('argument-hint', '')
88
-
89
- category, subcategory = categorize_command(file_path)
90
- usage_scenario = determine_usage_scenario(name, description, category)
91
- difficulty = determine_difficulty(name, description, category)
92
-
93
- # Build relative path from INDEX_DIR (need to go up 3 levels: index -> ccw-help -> skills -> .claude)
94
- # e.g., "../../../commands/workflow/lite-plan.md"
95
- rel_from_base = file_path.relative_to(BASE_DIR)
96
- rel_path = "../../../" + str(rel_from_base).replace('\\', '/')
97
-
98
- # Build full command name
99
- if ':' in name:
100
- command_name = f"/{name}"
101
- elif category == "general":
102
- command_name = f"/{name}"
103
- else:
104
- if subcategory:
105
- command_name = f"/{category}:{subcategory}:{name}"
106
- else:
107
- command_name = f"/{category}:{name}"
108
-
109
- return {
110
- "name": name,
111
- "command": command_name,
112
- "description": description,
113
- "arguments": argument_hint,
114
- "category": category,
115
- "subcategory": subcategory,
116
- "usage_scenario": usage_scenario,
117
- "difficulty": difficulty,
118
- "source": rel_path # Relative from index/ dir (e.g., "../../../commands/workflow/...")
119
- }
120
-
121
- def analyze_agent_file(file_path: Path) -> Dict[str, Any]:
122
- """Analyze a single agent file and extract metadata."""
123
- with open(file_path, 'r', encoding='utf-8') as f:
124
- content = f.read()
125
-
126
- frontmatter = parse_frontmatter(content)
127
-
128
- name = frontmatter.get('name', file_path.stem)
129
- description = frontmatter.get('description', '')
130
-
131
- # Build relative path from INDEX_DIR (need to go up 3 levels)
132
- # e.g., "../../../agents/code-developer.md"
133
- rel_from_base = file_path.relative_to(BASE_DIR)
134
- rel_path = "../../../" + str(rel_from_base).replace('\\', '/')
135
-
136
- return {
137
- "name": name,
138
- "description": description,
139
- "source": rel_path # Relative from index/ dir (e.g., "../../../agents/...")
140
- }
141
-
142
- def build_command_relationships() -> Dict[str, Any]:
143
- """Build command relationship mappings."""
144
- return {
145
- "workflow:plan": {
146
- "calls_internally": ["workflow:session:start", "workflow:tools:context-gather", "workflow:tools:conflict-resolution", "workflow:tools:task-generate-agent"],
147
- "next_steps": ["workflow:action-plan-verify", "workflow:status", "workflow:execute"],
148
- "alternatives": ["workflow:tdd-plan"],
149
- "prerequisites": []
150
- },
151
- "workflow:tdd-plan": {
152
- "calls_internally": ["workflow:session:start", "workflow:tools:context-gather", "workflow:tools:task-generate-tdd"],
153
- "next_steps": ["workflow:tdd-verify", "workflow:status", "workflow:execute"],
154
- "alternatives": ["workflow:plan"],
155
- "prerequisites": []
156
- },
157
- "workflow:execute": {
158
- "prerequisites": ["workflow:plan", "workflow:tdd-plan"],
159
- "related": ["workflow:status", "workflow:resume"],
160
- "next_steps": ["workflow:review", "workflow:tdd-verify"]
161
- },
162
- "workflow:action-plan-verify": {
163
- "prerequisites": ["workflow:plan"],
164
- "next_steps": ["workflow:execute"],
165
- "related": ["workflow:status"]
166
- },
167
- "workflow:tdd-verify": {
168
- "prerequisites": ["workflow:execute"],
169
- "related": ["workflow:tools:tdd-coverage-analysis"]
170
- },
171
- "workflow:session:start": {
172
- "next_steps": ["workflow:plan", "workflow:execute"],
173
- "related": ["workflow:session:list", "workflow:session:resume"]
174
- },
175
- "workflow:session:resume": {
176
- "alternatives": ["workflow:resume"],
177
- "related": ["workflow:session:list", "workflow:status"]
178
- },
179
- "workflow:lite-plan": {
180
- "calls_internally": ["workflow:lite-execute"],
181
- "next_steps": ["workflow:lite-execute", "workflow:status"],
182
- "alternatives": ["workflow:plan"],
183
- "prerequisites": []
184
- },
185
- "workflow:lite-fix": {
186
- "next_steps": ["workflow:lite-execute", "workflow:status"],
187
- "alternatives": ["workflow:lite-plan"],
188
- "related": ["workflow:test-cycle-execute"]
189
- },
190
- "workflow:lite-execute": {
191
- "prerequisites": ["workflow:lite-plan", "workflow:lite-fix"],
192
- "related": ["workflow:execute", "workflow:status"]
193
- },
194
- "workflow:review-session-cycle": {
195
- "prerequisites": ["workflow:execute"],
196
- "next_steps": ["workflow:review-fix"],
197
- "related": ["workflow:review-module-cycle"]
198
- },
199
- "workflow:review-fix": {
200
- "prerequisites": ["workflow:review-module-cycle", "workflow:review-session-cycle"],
201
- "related": ["workflow:test-cycle-execute"]
202
- },
203
- "memory:docs": {
204
- "calls_internally": ["workflow:session:start", "workflow:tools:context-gather"],
205
- "next_steps": ["workflow:execute"]
206
- },
207
- "memory:skill-memory": {
208
- "next_steps": ["workflow:plan", "cli:analyze"],
209
- "related": ["memory:load-skill-memory"]
210
- }
211
- }
212
-
213
- def identify_essential_commands(all_commands: List[Dict]) -> List[Dict]:
214
- """Identify the most essential commands for beginners."""
215
- essential_names = [
216
- "workflow:lite-plan", "workflow:lite-fix", "workflow:plan",
217
- "workflow:execute", "workflow:status", "workflow:session:start",
218
- "workflow:review-session-cycle", "cli:analyze", "cli:chat",
219
- "memory:docs", "workflow:brainstorm:artifacts",
220
- "workflow:action-plan-verify", "workflow:resume", "version"
221
- ]
222
-
223
- essential = []
224
- for cmd in all_commands:
225
- cmd_name = cmd['command'].lstrip('/')
226
- if cmd_name in essential_names:
227
- essential.append(cmd)
228
-
229
- essential.sort(key=lambda x: essential_names.index(x['command'].lstrip('/')) if x['command'].lstrip('/') in essential_names else 999)
230
- return essential[:14]
231
-
232
- def main():
233
- """Main analysis function."""
234
- import sys
235
- import io
236
-
237
- if sys.platform == 'win32':
238
- sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
239
-
240
- print("=== CCW-Help Index Rebuild ===\n")
241
-
242
- # Analyze command files
243
- print("=== Analyzing Command Files ===")
244
- command_files = list(COMMANDS_DIR.rglob("*.md"))
245
- print(f"Found {len(command_files)} command files")
246
-
247
- all_commands = []
248
- for cmd_file in sorted(command_files):
249
- try:
250
- metadata = analyze_command_file(cmd_file)
251
- all_commands.append(metadata)
252
- print(f" OK {metadata['command']}")
253
- except Exception as e:
254
- print(f" ERROR analyzing {cmd_file}: {e}")
255
-
256
- # Analyze agent files
257
- print("\n=== Analyzing Agent Files ===")
258
- agent_files = list(AGENTS_DIR.rglob("*.md"))
259
- print(f"Found {len(agent_files)} agent files")
260
-
261
- all_agents = []
262
- for agent_file in sorted(agent_files):
263
- try:
264
- metadata = analyze_agent_file(agent_file)
265
- all_agents.append(metadata)
266
- print(f" OK {metadata['name']}")
267
- except Exception as e:
268
- print(f" ERROR analyzing {agent_file}: {e}")
269
-
270
- print(f"\nAnalyzed {len(all_commands)} commands, {len(all_agents)} agents")
271
-
272
- # Generate index files
273
- INDEX_DIR.mkdir(parents=True, exist_ok=True)
274
-
275
- # 1. all-commands.json
276
- all_commands_path = INDEX_DIR / "all-commands.json"
277
- with open(all_commands_path, 'w', encoding='utf-8') as f:
278
- json.dump(all_commands, f, indent=2, ensure_ascii=False)
279
- print(f"\nOK Generated {all_commands_path.name} ({os.path.getsize(all_commands_path)} bytes)")
280
-
281
- # 2. all-agents.json
282
- all_agents_path = INDEX_DIR / "all-agents.json"
283
- with open(all_agents_path, 'w', encoding='utf-8') as f:
284
- json.dump(all_agents, f, indent=2, ensure_ascii=False)
285
- print(f"OK Generated {all_agents_path.name} ({os.path.getsize(all_agents_path)} bytes)")
286
-
287
- # 3. by-category.json
288
- by_category = defaultdict(lambda: defaultdict(list))
289
- for cmd in all_commands:
290
- cat = cmd['category']
291
- subcat = cmd['subcategory'] or '_root'
292
- by_category[cat][subcat].append(cmd)
293
-
294
- by_category_path = INDEX_DIR / "by-category.json"
295
- with open(by_category_path, 'w', encoding='utf-8') as f:
296
- json.dump(dict(by_category), f, indent=2, ensure_ascii=False)
297
- print(f"OK Generated {by_category_path.name} ({os.path.getsize(by_category_path)} bytes)")
298
-
299
- # 4. by-use-case.json
300
- by_use_case = defaultdict(list)
301
- for cmd in all_commands:
302
- by_use_case[cmd['usage_scenario']].append(cmd)
303
-
304
- by_use_case_path = INDEX_DIR / "by-use-case.json"
305
- with open(by_use_case_path, 'w', encoding='utf-8') as f:
306
- json.dump(dict(by_use_case), f, indent=2, ensure_ascii=False)
307
- print(f"OK Generated {by_use_case_path.name} ({os.path.getsize(by_use_case_path)} bytes)")
308
-
309
- # 5. essential-commands.json
310
- essential = identify_essential_commands(all_commands)
311
- essential_path = INDEX_DIR / "essential-commands.json"
312
- with open(essential_path, 'w', encoding='utf-8') as f:
313
- json.dump(essential, f, indent=2, ensure_ascii=False)
314
- print(f"OK Generated {essential_path.name} ({os.path.getsize(essential_path)} bytes)")
315
-
316
- # 6. command-relationships.json
317
- relationships = build_command_relationships()
318
- relationships_path = INDEX_DIR / "command-relationships.json"
319
- with open(relationships_path, 'w', encoding='utf-8') as f:
320
- json.dump(relationships, f, indent=2, ensure_ascii=False)
321
- print(f"OK Generated {relationships_path.name} ({os.path.getsize(relationships_path)} bytes)")
322
-
323
- # Print summary
324
- print("\n=== Summary ===")
325
- print(f"Commands: {len(all_commands)}")
326
- print(f"Agents: {len(all_agents)}")
327
- print(f"Essential: {len(essential)}")
328
- print(f"\nBy category:")
329
- for cat in sorted(by_category.keys()):
330
- total = sum(len(cmds) for cmds in by_category[cat].values())
331
- print(f" {cat}: {total}")
332
-
333
- print(f"\nIndex: {INDEX_DIR}")
334
- print("=== Complete ===")
335
-
336
- if __name__ == '__main__':
337
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ Analyze all command/agent files and generate index files for ccw-help skill.
4
+ Outputs relative paths pointing to source files (no reference folder duplication).
5
+ """
6
+
7
+ import os
8
+ import re
9
+ import json
10
+ from pathlib import Path
11
+ from collections import defaultdict
12
+ from typing import Dict, List, Any
13
+
14
+ # Base paths
15
+ BASE_DIR = Path("D:/Claude_dms3/.claude")
16
+ COMMANDS_DIR = BASE_DIR / "commands"
17
+ AGENTS_DIR = BASE_DIR / "agents"
18
+ SKILL_DIR = BASE_DIR / "skills" / "ccw-help"
19
+ INDEX_DIR = SKILL_DIR / "index"
20
+
21
+ def parse_frontmatter(content: str) -> Dict[str, Any]:
22
+ """Extract YAML frontmatter from markdown content."""
23
+ frontmatter = {}
24
+ if content.startswith('---'):
25
+ lines = content.split('\n')
26
+ for i, line in enumerate(lines[1:], 1):
27
+ if line.strip() == '---':
28
+ break
29
+ if ':' in line:
30
+ key, value = line.split(':', 1)
31
+ frontmatter[key.strip()] = value.strip().strip('"')
32
+ return frontmatter
33
+
34
+ def categorize_command(file_path: Path) -> tuple:
35
+ """Determine category and subcategory from file path."""
36
+ parts = file_path.relative_to(COMMANDS_DIR).parts
37
+
38
+ if len(parts) == 1:
39
+ return "general", None
40
+
41
+ category = parts[0] # cli, memory, task, workflow
42
+ subcategory = parts[1].replace('.md', '') if len(parts) > 2 else None
43
+
44
+ return category, subcategory
45
+
46
+ def determine_usage_scenario(name: str, description: str, category: str) -> str:
47
+ """Determine primary usage scenario for command."""
48
+ name_lower = name.lower()
49
+
50
+ if any(word in name_lower for word in ['plan', 'design', 'breakdown', 'brainstorm']):
51
+ return "planning"
52
+ if any(word in name_lower for word in ['implement', 'execute', 'generate', 'create', 'write']):
53
+ return "implementation"
54
+ if any(word in name_lower for word in ['test', 'tdd', 'verify', 'coverage']):
55
+ return "testing"
56
+ if any(word in name_lower for word in ['docs', 'documentation', 'memory']):
57
+ return "documentation"
58
+ if any(word in name_lower for word in ['session', 'resume', 'status', 'complete']):
59
+ return "session-management"
60
+ if any(word in name_lower for word in ['analyze', 'review', 'diagnosis']):
61
+ return "analysis"
62
+ return "general"
63
+
64
+ def determine_difficulty(name: str, description: str, category: str) -> str:
65
+ """Determine difficulty level."""
66
+ name_lower = name.lower()
67
+
68
+ beginner_keywords = ['status', 'list', 'chat', 'analyze', 'version']
69
+ if any(word in name_lower for word in beginner_keywords):
70
+ return "Beginner"
71
+
72
+ advanced_keywords = ['tdd', 'conflict', 'agent', 'auto-parallel', 'coverage', 'synthesis']
73
+ if any(word in name_lower for word in advanced_keywords):
74
+ return "Advanced"
75
+
76
+ return "Intermediate"
77
+
78
+ def analyze_command_file(file_path: Path) -> Dict[str, Any]:
79
+ """Analyze a single command file and extract metadata."""
80
+ with open(file_path, 'r', encoding='utf-8') as f:
81
+ content = f.read()
82
+
83
+ frontmatter = parse_frontmatter(content)
84
+
85
+ name = frontmatter.get('name', file_path.stem)
86
+ description = frontmatter.get('description', '')
87
+ argument_hint = frontmatter.get('argument-hint', '')
88
+
89
+ category, subcategory = categorize_command(file_path)
90
+ usage_scenario = determine_usage_scenario(name, description, category)
91
+ difficulty = determine_difficulty(name, description, category)
92
+
93
+ # Build relative path from INDEX_DIR (need to go up 3 levels: index -> ccw-help -> skills -> .claude)
94
+ # e.g., "../../../commands/workflow/lite-plan.md"
95
+ rel_from_base = file_path.relative_to(BASE_DIR)
96
+ rel_path = "../../../" + str(rel_from_base).replace('\\', '/')
97
+
98
+ # Build full command name
99
+ if ':' in name:
100
+ command_name = f"/{name}"
101
+ elif category == "general":
102
+ command_name = f"/{name}"
103
+ else:
104
+ if subcategory:
105
+ command_name = f"/{category}:{subcategory}:{name}"
106
+ else:
107
+ command_name = f"/{category}:{name}"
108
+
109
+ return {
110
+ "name": name,
111
+ "command": command_name,
112
+ "description": description,
113
+ "arguments": argument_hint,
114
+ "category": category,
115
+ "subcategory": subcategory,
116
+ "usage_scenario": usage_scenario,
117
+ "difficulty": difficulty,
118
+ "source": rel_path # Relative from index/ dir (e.g., "../../../commands/workflow/...")
119
+ }
120
+
121
+ def analyze_agent_file(file_path: Path) -> Dict[str, Any]:
122
+ """Analyze a single agent file and extract metadata."""
123
+ with open(file_path, 'r', encoding='utf-8') as f:
124
+ content = f.read()
125
+
126
+ frontmatter = parse_frontmatter(content)
127
+
128
+ name = frontmatter.get('name', file_path.stem)
129
+ description = frontmatter.get('description', '')
130
+
131
+ # Build relative path from INDEX_DIR (need to go up 3 levels)
132
+ # e.g., "../../../agents/code-developer.md"
133
+ rel_from_base = file_path.relative_to(BASE_DIR)
134
+ rel_path = "../../../" + str(rel_from_base).replace('\\', '/')
135
+
136
+ return {
137
+ "name": name,
138
+ "description": description,
139
+ "source": rel_path # Relative from index/ dir (e.g., "../../../agents/...")
140
+ }
141
+
142
+ def build_command_relationships() -> Dict[str, Any]:
143
+ """Build command relationship mappings."""
144
+ return {
145
+ "workflow:plan": {
146
+ "calls_internally": ["workflow:session:start", "workflow:tools:context-gather", "workflow:tools:conflict-resolution", "workflow:tools:task-generate-agent"],
147
+ "next_steps": ["workflow:plan-verify", "workflow:status", "workflow:execute"],
148
+ "alternatives": ["workflow:tdd-plan"],
149
+ "prerequisites": []
150
+ },
151
+ "workflow:tdd-plan": {
152
+ "calls_internally": ["workflow:session:start", "workflow:tools:context-gather", "workflow:tools:task-generate-tdd"],
153
+ "next_steps": ["workflow:tdd-verify", "workflow:status", "workflow:execute"],
154
+ "alternatives": ["workflow:plan"],
155
+ "prerequisites": []
156
+ },
157
+ "workflow:execute": {
158
+ "prerequisites": ["workflow:plan", "workflow:tdd-plan"],
159
+ "related": ["workflow:status", "workflow:resume"],
160
+ "next_steps": ["workflow:review", "workflow:tdd-verify"]
161
+ },
162
+ "workflow:plan-verify": {
163
+ "prerequisites": ["workflow:plan"],
164
+ "next_steps": ["workflow:execute"],
165
+ "related": ["workflow:status"]
166
+ },
167
+ "workflow:tdd-verify": {
168
+ "prerequisites": ["workflow:execute"],
169
+ "related": ["workflow:tools:tdd-coverage-analysis"]
170
+ },
171
+ "workflow:session:start": {
172
+ "next_steps": ["workflow:plan", "workflow:execute"],
173
+ "related": ["workflow:session:list", "workflow:session:resume"]
174
+ },
175
+ "workflow:session:resume": {
176
+ "alternatives": ["workflow:resume"],
177
+ "related": ["workflow:session:list", "workflow:status"]
178
+ },
179
+ "workflow:lite-plan": {
180
+ "calls_internally": ["workflow:lite-execute"],
181
+ "next_steps": ["workflow:lite-execute", "workflow:status"],
182
+ "alternatives": ["workflow:plan"],
183
+ "prerequisites": []
184
+ },
185
+ "workflow:lite-fix": {
186
+ "next_steps": ["workflow:lite-execute", "workflow:status"],
187
+ "alternatives": ["workflow:lite-plan"],
188
+ "related": ["workflow:test-cycle-execute"]
189
+ },
190
+ "workflow:lite-execute": {
191
+ "prerequisites": ["workflow:lite-plan", "workflow:lite-fix"],
192
+ "related": ["workflow:execute", "workflow:status"]
193
+ },
194
+ "workflow:review-session-cycle": {
195
+ "prerequisites": ["workflow:execute"],
196
+ "next_steps": ["workflow:review-fix"],
197
+ "related": ["workflow:review-module-cycle"]
198
+ },
199
+ "workflow:review-fix": {
200
+ "prerequisites": ["workflow:review-module-cycle", "workflow:review-session-cycle"],
201
+ "related": ["workflow:test-cycle-execute"]
202
+ },
203
+ "memory:docs": {
204
+ "calls_internally": ["workflow:session:start", "workflow:tools:context-gather"],
205
+ "next_steps": ["workflow:execute"]
206
+ },
207
+ "memory:skill-memory": {
208
+ "next_steps": ["workflow:plan", "cli:analyze"],
209
+ "related": ["memory:load-skill-memory"]
210
+ }
211
+ }
212
+
213
+ def identify_essential_commands(all_commands: List[Dict]) -> List[Dict]:
214
+ """Identify the most essential commands for beginners."""
215
+ essential_names = [
216
+ "workflow:lite-plan", "workflow:lite-fix", "workflow:plan",
217
+ "workflow:execute", "workflow:status", "workflow:session:start",
218
+ "workflow:review-session-cycle", "cli:analyze", "cli:chat",
219
+ "memory:docs", "workflow:brainstorm:artifacts",
220
+ "workflow:plan-verify", "workflow:resume", "version"
221
+ ]
222
+
223
+ essential = []
224
+ for cmd in all_commands:
225
+ cmd_name = cmd['command'].lstrip('/')
226
+ if cmd_name in essential_names:
227
+ essential.append(cmd)
228
+
229
+ essential.sort(key=lambda x: essential_names.index(x['command'].lstrip('/')) if x['command'].lstrip('/') in essential_names else 999)
230
+ return essential[:14]
231
+
232
+ def main():
233
+ """Main analysis function."""
234
+ import sys
235
+ import io
236
+
237
+ if sys.platform == 'win32':
238
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
239
+
240
+ print("=== CCW-Help Index Rebuild ===\n")
241
+
242
+ # Analyze command files
243
+ print("=== Analyzing Command Files ===")
244
+ command_files = list(COMMANDS_DIR.rglob("*.md"))
245
+ print(f"Found {len(command_files)} command files")
246
+
247
+ all_commands = []
248
+ for cmd_file in sorted(command_files):
249
+ try:
250
+ metadata = analyze_command_file(cmd_file)
251
+ all_commands.append(metadata)
252
+ print(f" OK {metadata['command']}")
253
+ except Exception as e:
254
+ print(f" ERROR analyzing {cmd_file}: {e}")
255
+
256
+ # Analyze agent files
257
+ print("\n=== Analyzing Agent Files ===")
258
+ agent_files = list(AGENTS_DIR.rglob("*.md"))
259
+ print(f"Found {len(agent_files)} agent files")
260
+
261
+ all_agents = []
262
+ for agent_file in sorted(agent_files):
263
+ try:
264
+ metadata = analyze_agent_file(agent_file)
265
+ all_agents.append(metadata)
266
+ print(f" OK {metadata['name']}")
267
+ except Exception as e:
268
+ print(f" ERROR analyzing {agent_file}: {e}")
269
+
270
+ print(f"\nAnalyzed {len(all_commands)} commands, {len(all_agents)} agents")
271
+
272
+ # Generate index files
273
+ INDEX_DIR.mkdir(parents=True, exist_ok=True)
274
+
275
+ # 1. all-commands.json
276
+ all_commands_path = INDEX_DIR / "all-commands.json"
277
+ with open(all_commands_path, 'w', encoding='utf-8') as f:
278
+ json.dump(all_commands, f, indent=2, ensure_ascii=False)
279
+ print(f"\nOK Generated {all_commands_path.name} ({os.path.getsize(all_commands_path)} bytes)")
280
+
281
+ # 2. all-agents.json
282
+ all_agents_path = INDEX_DIR / "all-agents.json"
283
+ with open(all_agents_path, 'w', encoding='utf-8') as f:
284
+ json.dump(all_agents, f, indent=2, ensure_ascii=False)
285
+ print(f"OK Generated {all_agents_path.name} ({os.path.getsize(all_agents_path)} bytes)")
286
+
287
+ # 3. by-category.json
288
+ by_category = defaultdict(lambda: defaultdict(list))
289
+ for cmd in all_commands:
290
+ cat = cmd['category']
291
+ subcat = cmd['subcategory'] or '_root'
292
+ by_category[cat][subcat].append(cmd)
293
+
294
+ by_category_path = INDEX_DIR / "by-category.json"
295
+ with open(by_category_path, 'w', encoding='utf-8') as f:
296
+ json.dump(dict(by_category), f, indent=2, ensure_ascii=False)
297
+ print(f"OK Generated {by_category_path.name} ({os.path.getsize(by_category_path)} bytes)")
298
+
299
+ # 4. by-use-case.json
300
+ by_use_case = defaultdict(list)
301
+ for cmd in all_commands:
302
+ by_use_case[cmd['usage_scenario']].append(cmd)
303
+
304
+ by_use_case_path = INDEX_DIR / "by-use-case.json"
305
+ with open(by_use_case_path, 'w', encoding='utf-8') as f:
306
+ json.dump(dict(by_use_case), f, indent=2, ensure_ascii=False)
307
+ print(f"OK Generated {by_use_case_path.name} ({os.path.getsize(by_use_case_path)} bytes)")
308
+
309
+ # 5. essential-commands.json
310
+ essential = identify_essential_commands(all_commands)
311
+ essential_path = INDEX_DIR / "essential-commands.json"
312
+ with open(essential_path, 'w', encoding='utf-8') as f:
313
+ json.dump(essential, f, indent=2, ensure_ascii=False)
314
+ print(f"OK Generated {essential_path.name} ({os.path.getsize(essential_path)} bytes)")
315
+
316
+ # 6. command-relationships.json
317
+ relationships = build_command_relationships()
318
+ relationships_path = INDEX_DIR / "command-relationships.json"
319
+ with open(relationships_path, 'w', encoding='utf-8') as f:
320
+ json.dump(relationships, f, indent=2, ensure_ascii=False)
321
+ print(f"OK Generated {relationships_path.name} ({os.path.getsize(relationships_path)} bytes)")
322
+
323
+ # Print summary
324
+ print("\n=== Summary ===")
325
+ print(f"Commands: {len(all_commands)}")
326
+ print(f"Agents: {len(all_agents)}")
327
+ print(f"Essential: {len(essential)}")
328
+ print(f"\nBy category:")
329
+ for cat in sorted(by_category.keys()):
330
+ total = sum(len(cmds) for cmds in by_category[cat].values())
331
+ print(f" {cat}: {total}")
332
+
333
+ print(f"\nIndex: {INDEX_DIR}")
334
+ print("=== Complete ===")
335
+
336
+ if __name__ == '__main__':
337
+ main()