@codihaus/claude-skills 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.
- package/README.md +167 -0
- package/bin/cli.js +58 -0
- package/package.json +46 -0
- package/skills/_quality-attributes.md +392 -0
- package/skills/_registry.md +189 -0
- package/skills/debrief/SKILL.md +647 -0
- package/skills/debrief/references/change-request-template.md +124 -0
- package/skills/debrief/references/file-patterns.md +173 -0
- package/skills/debrief/references/group-codes.md +72 -0
- package/skills/debrief/references/research-queries.md +106 -0
- package/skills/debrief/references/use-case-template.md +141 -0
- package/skills/debrief/scripts/generate_questionnaire.py +195 -0
- package/skills/dev-arch/SKILL.md +747 -0
- package/skills/dev-changelog/SKILL.md +378 -0
- package/skills/dev-coding/SKILL.md +470 -0
- package/skills/dev-coding-backend/SKILL.md +361 -0
- package/skills/dev-coding-frontend/SKILL.md +534 -0
- package/skills/dev-coding-frontend/references/nextjs.md +477 -0
- package/skills/dev-review/SKILL.md +548 -0
- package/skills/dev-scout/SKILL.md +723 -0
- package/skills/dev-scout/references/feature-patterns.md +210 -0
- package/skills/dev-scout/references/file-patterns.md +252 -0
- package/skills/dev-scout/references/tech-detection.md +211 -0
- package/skills/dev-scout/scripts/scout-analyze.sh +280 -0
- package/skills/dev-specs/SKILL.md +577 -0
- package/skills/dev-specs/references/checklist.md +176 -0
- package/skills/dev-specs/references/spec-templates.md +460 -0
- package/skills/dev-test/SKILL.md +364 -0
- package/skills/utils/diagram/SKILL.md +205 -0
- package/skills/utils/diagram/references/common-errors.md +305 -0
- package/skills/utils/diagram/references/diagram-types.md +636 -0
- package/skills/utils/docs-graph/SKILL.md +204 -0
- package/skills/utils/gemini/SKILL.md +292 -0
- package/skills/utils/gemini/scripts/gemini-scan.py +340 -0
- package/skills/utils/gemini/scripts/setup.sh +169 -0
- package/src/commands/add.js +64 -0
- package/src/commands/doctor.js +179 -0
- package/src/commands/init.js +251 -0
- package/src/commands/list.js +88 -0
- package/src/commands/remove.js +60 -0
- package/src/commands/update.js +72 -0
- package/src/index.js +26 -0
- package/src/utils/config.js +272 -0
- package/src/utils/deps.js +599 -0
- package/src/utils/skills.js +253 -0
- package/templates/CLAUDE.md.template +58 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Generate dynamic questionnaire based on debrief gaps.
|
|
4
|
+
Called at end of debrief with identified open questions.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python generate_questionnaire.py output.xlsx questions.json
|
|
8
|
+
|
|
9
|
+
questions.json format:
|
|
10
|
+
{
|
|
11
|
+
"project_name": "Project Name",
|
|
12
|
+
"date": "2024-01-20",
|
|
13
|
+
"questions": [
|
|
14
|
+
{
|
|
15
|
+
"category": "Requirements",
|
|
16
|
+
"question": "What is the expected user load?",
|
|
17
|
+
"priority": "Required",
|
|
18
|
+
"context": "Needed for infrastructure planning",
|
|
19
|
+
"source": "UC-PAY-003"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import sys
|
|
26
|
+
import json
|
|
27
|
+
from openpyxl import Workbook
|
|
28
|
+
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
|
|
29
|
+
from openpyxl.utils import get_column_letter
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_questionnaire(output_path: str, questions_data: dict):
|
|
33
|
+
wb = Workbook()
|
|
34
|
+
ws = wb.active
|
|
35
|
+
ws.title = "Questions"
|
|
36
|
+
|
|
37
|
+
# Styles
|
|
38
|
+
header_font = Font(bold=True, color="FFFFFF", size=12)
|
|
39
|
+
header_fill = PatternFill("solid", fgColor="4472C4")
|
|
40
|
+
required_fill = PatternFill("solid", fgColor="FCE4D6")
|
|
41
|
+
optional_fill = PatternFill("solid", fgColor="E2EFDA")
|
|
42
|
+
border = Border(
|
|
43
|
+
left=Side(style='thin'),
|
|
44
|
+
right=Side(style='thin'),
|
|
45
|
+
top=Side(style='thin'),
|
|
46
|
+
bottom=Side(style='thin')
|
|
47
|
+
)
|
|
48
|
+
wrap_alignment = Alignment(wrap_text=True, vertical='top')
|
|
49
|
+
|
|
50
|
+
# Title row
|
|
51
|
+
ws.merge_cells('A1:E1')
|
|
52
|
+
title_cell = ws['A1']
|
|
53
|
+
title_cell.value = f"Questions for: {questions_data.get('project_name', 'Project')}"
|
|
54
|
+
title_cell.font = Font(bold=True, size=14)
|
|
55
|
+
title_cell.alignment = Alignment(horizontal='center')
|
|
56
|
+
|
|
57
|
+
# Date row
|
|
58
|
+
ws.merge_cells('A2:E2')
|
|
59
|
+
ws['A2'] = f"Generated: {questions_data.get('date', '')}"
|
|
60
|
+
ws['A2'].font = Font(italic=True, color="666666")
|
|
61
|
+
ws['A2'].alignment = Alignment(horizontal='center')
|
|
62
|
+
|
|
63
|
+
# Headers
|
|
64
|
+
headers = ["Category", "Question", "Priority", "Answer", "Context/Source"]
|
|
65
|
+
col_widths = [15, 45, 12, 40, 25]
|
|
66
|
+
|
|
67
|
+
for col, (header, width) in enumerate(zip(headers, col_widths), 1):
|
|
68
|
+
cell = ws.cell(row=4, column=col, value=header)
|
|
69
|
+
cell.font = header_font
|
|
70
|
+
cell.fill = header_fill
|
|
71
|
+
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
72
|
+
cell.border = border
|
|
73
|
+
ws.column_dimensions[get_column_letter(col)].width = width
|
|
74
|
+
|
|
75
|
+
# Questions
|
|
76
|
+
questions = questions_data.get('questions', [])
|
|
77
|
+
|
|
78
|
+
for row_idx, q in enumerate(questions, 5):
|
|
79
|
+
category = q.get('category', 'General')
|
|
80
|
+
question = q.get('question', '')
|
|
81
|
+
priority = q.get('priority', 'Optional')
|
|
82
|
+
context = q.get('context', '')
|
|
83
|
+
source = q.get('source', '')
|
|
84
|
+
|
|
85
|
+
# Combine context and source
|
|
86
|
+
context_text = context
|
|
87
|
+
if source:
|
|
88
|
+
context_text = f"{context}\n[Source: {source}]" if context else f"[Source: {source}]"
|
|
89
|
+
|
|
90
|
+
ws.cell(row=row_idx, column=1, value=category).border = border
|
|
91
|
+
|
|
92
|
+
q_cell = ws.cell(row=row_idx, column=2, value=question)
|
|
93
|
+
q_cell.border = border
|
|
94
|
+
q_cell.alignment = wrap_alignment
|
|
95
|
+
|
|
96
|
+
priority_cell = ws.cell(row=row_idx, column=3, value=priority)
|
|
97
|
+
priority_cell.border = border
|
|
98
|
+
priority_cell.alignment = Alignment(horizontal='center')
|
|
99
|
+
if priority == "Required":
|
|
100
|
+
priority_cell.fill = required_fill
|
|
101
|
+
else:
|
|
102
|
+
priority_cell.fill = optional_fill
|
|
103
|
+
|
|
104
|
+
ws.cell(row=row_idx, column=4, value="").border = border
|
|
105
|
+
|
|
106
|
+
ctx_cell = ws.cell(row=row_idx, column=5, value=context_text)
|
|
107
|
+
ctx_cell.border = border
|
|
108
|
+
ctx_cell.alignment = wrap_alignment
|
|
109
|
+
ctx_cell.font = Font(italic=True, color="666666", size=10)
|
|
110
|
+
|
|
111
|
+
# Set row heights
|
|
112
|
+
ws.row_dimensions[1].height = 25
|
|
113
|
+
ws.row_dimensions[4].height = 25
|
|
114
|
+
for row in range(5, len(questions) + 5):
|
|
115
|
+
ws.row_dimensions[row].height = 35
|
|
116
|
+
|
|
117
|
+
# Freeze header row
|
|
118
|
+
ws.freeze_panes = 'A5'
|
|
119
|
+
|
|
120
|
+
# Summary sheet
|
|
121
|
+
ws_summary = wb.create_sheet("Summary", 0)
|
|
122
|
+
summary_data = [
|
|
123
|
+
("Project Questionnaire", ""),
|
|
124
|
+
("", ""),
|
|
125
|
+
("Project:", questions_data.get('project_name', '')),
|
|
126
|
+
("Generated:", questions_data.get('date', '')),
|
|
127
|
+
("Total Questions:", len(questions)),
|
|
128
|
+
("", ""),
|
|
129
|
+
("Priority Breakdown:", ""),
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
# Count priorities
|
|
133
|
+
required_count = sum(1 for q in questions if q.get('priority') == 'Required')
|
|
134
|
+
optional_count = len(questions) - required_count
|
|
135
|
+
|
|
136
|
+
summary_data.extend([
|
|
137
|
+
("Required:", required_count),
|
|
138
|
+
("Optional:", optional_count),
|
|
139
|
+
("", ""),
|
|
140
|
+
("Categories:", ""),
|
|
141
|
+
])
|
|
142
|
+
|
|
143
|
+
# Count categories
|
|
144
|
+
categories = {}
|
|
145
|
+
for q in questions:
|
|
146
|
+
cat = q.get('category', 'General')
|
|
147
|
+
categories[cat] = categories.get(cat, 0) + 1
|
|
148
|
+
|
|
149
|
+
for cat, count in sorted(categories.items()):
|
|
150
|
+
summary_data.append((f" {cat}:", count))
|
|
151
|
+
|
|
152
|
+
summary_data.extend([
|
|
153
|
+
("", ""),
|
|
154
|
+
("Instructions:", ""),
|
|
155
|
+
("1.", "Fill in the 'Answer' column for each question"),
|
|
156
|
+
("2.", "Required questions must be answered before proceeding"),
|
|
157
|
+
("3.", "Context/Source shows where this question originated"),
|
|
158
|
+
("4.", "Save and return this file when complete"),
|
|
159
|
+
])
|
|
160
|
+
|
|
161
|
+
for row, (col1, col2) in enumerate(summary_data, 1):
|
|
162
|
+
ws_summary.cell(row=row, column=1, value=col1)
|
|
163
|
+
ws_summary.cell(row=row, column=2, value=col2)
|
|
164
|
+
if row == 1:
|
|
165
|
+
ws_summary.cell(row=row, column=1).font = Font(bold=True, size=14)
|
|
166
|
+
elif col1.endswith(':') and col2 != "":
|
|
167
|
+
ws_summary.cell(row=row, column=1).font = Font(bold=True)
|
|
168
|
+
|
|
169
|
+
ws_summary.column_dimensions['A'].width = 25
|
|
170
|
+
ws_summary.column_dimensions['B'].width = 40
|
|
171
|
+
|
|
172
|
+
# Save
|
|
173
|
+
wb.save(output_path)
|
|
174
|
+
print(f"Created: {output_path}")
|
|
175
|
+
print(f" - {len(questions)} questions")
|
|
176
|
+
print(f" - {required_count} required, {optional_count} optional")
|
|
177
|
+
return output_path
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
if __name__ == "__main__":
|
|
181
|
+
if len(sys.argv) < 3:
|
|
182
|
+
print("Usage: python generate_questionnaire.py output.xlsx questions.json")
|
|
183
|
+
print("\nOr pipe JSON: echo '{...}' | python generate_questionnaire.py output.xlsx -")
|
|
184
|
+
sys.exit(1)
|
|
185
|
+
|
|
186
|
+
output = sys.argv[1]
|
|
187
|
+
json_source = sys.argv[2]
|
|
188
|
+
|
|
189
|
+
if json_source == "-":
|
|
190
|
+
data = json.load(sys.stdin)
|
|
191
|
+
else:
|
|
192
|
+
with open(json_source, 'r') as f:
|
|
193
|
+
data = json.load(f)
|
|
194
|
+
|
|
195
|
+
create_questionnaire(output, data)
|