up-cli 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
- up/cli.py +27 -1
- up/commands/dashboard.py +248 -0
- up/commands/learn.py +381 -0
- up/commands/new.py +108 -10
- up/commands/start.py +414 -0
- up/commands/status.py +205 -0
- up/commands/summarize.py +122 -0
- up/context.py +367 -0
- up/summarizer.py +407 -0
- up/templates/__init__.py +70 -2
- up/templates/config/__init__.py +502 -20
- up/templates/learn/__init__.py +567 -14
- up/templates/loop/__init__.py +480 -21
- up/templates/mcp/__init__.py +474 -0
- up/templates/projects/__init__.py +786 -0
- up_cli-0.2.0.dist-info/METADATA +374 -0
- up_cli-0.2.0.dist-info/RECORD +23 -0
- up_cli-0.1.0.dist-info/METADATA +0 -186
- up_cli-0.1.0.dist-info/RECORD +0 -14
- {up_cli-0.1.0.dist-info → up_cli-0.2.0.dist-info}/WHEEL +0 -0
- {up_cli-0.1.0.dist-info → up_cli-0.2.0.dist-info}/entry_points.txt +0 -0
up/templates/learn/__init__.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Learn system templates."""
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from datetime import date
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def create_learn_system(target_dir: Path, ai_target: str, force: bool = False) -> None:
|
|
@@ -20,12 +21,16 @@ def create_learn_system(target_dir: Path, ai_target: str, force: bool = False) -
|
|
|
20
21
|
_create_skill_md(skill_dir, force)
|
|
21
22
|
_create_sources_json(skill_dir, force)
|
|
22
23
|
_create_patterns_md(skill_dir, force)
|
|
24
|
+
_create_gap_analysis_md(skill_dir, force)
|
|
25
|
+
_create_project_analyzer(skill_dir, force)
|
|
26
|
+
_create_prd_template(skill_dir, force)
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
def _write_file(path: Path, content: str, force: bool) -> None:
|
|
26
30
|
"""Write file if it doesn't exist or force is True."""
|
|
27
31
|
if path.exists() and not force:
|
|
28
32
|
return
|
|
33
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
29
34
|
path.write_text(content)
|
|
30
35
|
|
|
31
36
|
|
|
@@ -35,32 +40,206 @@ def _create_skill_md(skill_dir: Path, force: bool) -> None:
|
|
|
35
40
|
name: learn
|
|
36
41
|
description: Research and create improvement plans
|
|
37
42
|
user-invocable: true
|
|
38
|
-
allowed-tools: Read, Write, Bash, WebFetch, WebSearch
|
|
43
|
+
allowed-tools: Read, Write, Bash, WebFetch, WebSearch, Glob, Grep
|
|
44
|
+
version: "1.0.0"
|
|
45
|
+
min-claude-version: "2024.01"
|
|
39
46
|
---
|
|
40
47
|
|
|
41
48
|
# Learning System
|
|
42
49
|
|
|
43
|
-
Research best practices and create actionable plans.
|
|
50
|
+
Research best practices from open source projects and blogs, then create actionable improvement plans.
|
|
44
51
|
|
|
45
52
|
## Workflow
|
|
46
53
|
|
|
47
54
|
```
|
|
48
|
-
RESEARCH → ANALYZE → COMPARE → PLAN
|
|
55
|
+
RESEARCH → ANALYZE → COMPARE → PLAN → IMPLEMENT
|
|
49
56
|
```
|
|
50
57
|
|
|
51
58
|
## Commands
|
|
52
59
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
| Command | Description |
|
|
61
|
+
|---------|-------------|
|
|
62
|
+
| `/learn auto` | Auto-analyze project and generate insights |
|
|
63
|
+
| `/learn research [topic]` | Research a specific topic |
|
|
64
|
+
| `/learn analyze` | Analyze all research files |
|
|
65
|
+
| `/learn compare` | Compare findings with current code |
|
|
66
|
+
| `/learn plan` | Generate improvement PRD |
|
|
67
|
+
| `/learn full` | Run complete pipeline |
|
|
56
68
|
|
|
57
|
-
##
|
|
69
|
+
## Phase 1: RESEARCH
|
|
70
|
+
|
|
71
|
+
### Default Sources
|
|
72
|
+
|
|
73
|
+
Read `sources.json` for configured sources. Research from:
|
|
74
|
+
|
|
75
|
+
**Open Source Projects:**
|
|
76
|
+
- semgrep/semgrep - Pattern-based code analysis
|
|
77
|
+
- github/codeql - Query-based analysis
|
|
78
|
+
- High-quality projects in your tech stack
|
|
79
|
+
|
|
80
|
+
**Blogs & Documentation:**
|
|
81
|
+
- Official documentation for your frameworks
|
|
82
|
+
- Engineering blogs from top companies
|
|
83
|
+
|
|
84
|
+
### Actions
|
|
85
|
+
|
|
86
|
+
1. Use `WebSearch` to find recent articles/releases
|
|
87
|
+
2. Use `WebFetch` to read project READMEs and docs
|
|
88
|
+
3. Extract architecture patterns
|
|
89
|
+
4. Note innovative approaches
|
|
90
|
+
|
|
91
|
+
### Output
|
|
92
|
+
|
|
93
|
+
Save findings to `research/YYYY-MM-DD-topic.md`:
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
# Research: [Topic Name]
|
|
97
|
+
|
|
98
|
+
**Created**: YYYY-MM-DD
|
|
99
|
+
**Status**: 📋 Reference
|
|
100
|
+
**Source**: [Project/Blog Name]
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Key Findings
|
|
105
|
+
|
|
106
|
+
1. Finding 1
|
|
107
|
+
2. Finding 2
|
|
108
|
+
|
|
109
|
+
## Applicable Patterns
|
|
110
|
+
|
|
111
|
+
- Pattern A: Description
|
|
112
|
+
- Pattern B: Description
|
|
113
|
+
|
|
114
|
+
## Code Examples
|
|
115
|
+
|
|
116
|
+
```language
|
|
117
|
+
// example code
|
|
118
|
+
```
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Phase 2: ANALYZE
|
|
124
|
+
|
|
125
|
+
Read all research files and extract:
|
|
126
|
+
|
|
127
|
+
1. **Design Patterns** - Architectural approaches
|
|
128
|
+
2. **Key Innovations** - Novel techniques
|
|
129
|
+
3. **Best Practices** - Industry standards
|
|
130
|
+
4. **Reusable Components** - Code/concepts to adopt
|
|
131
|
+
|
|
132
|
+
### Output
|
|
133
|
+
|
|
134
|
+
Update `insights/patterns.md` with extracted patterns.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Phase 3: COMPARE
|
|
139
|
+
|
|
140
|
+
Compare insights with current implementation:
|
|
141
|
+
|
|
142
|
+
1. Read project's main documentation (CLAUDE.md, README.md)
|
|
143
|
+
2. Scan source code for current patterns
|
|
144
|
+
3. Identify gaps and opportunities
|
|
145
|
+
|
|
146
|
+
### Output
|
|
147
|
+
|
|
148
|
+
Update `insights/gap-analysis.md` with findings.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Phase 4: PLAN
|
|
153
|
+
|
|
154
|
+
Create improvement plan as PRD:
|
|
155
|
+
|
|
156
|
+
1. Prioritize gaps by impact/effort
|
|
157
|
+
2. Create user stories with acceptance criteria
|
|
158
|
+
3. Order by dependencies
|
|
159
|
+
4. Save as `prd.json`
|
|
160
|
+
|
|
161
|
+
### PRD Schema
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"project": "Project Name",
|
|
166
|
+
"branchName": "feature/improvements",
|
|
167
|
+
"description": "Brief description",
|
|
168
|
+
"userStories": [
|
|
169
|
+
{
|
|
170
|
+
"id": "US-001",
|
|
171
|
+
"title": "Story title",
|
|
172
|
+
"description": "Description",
|
|
173
|
+
"acceptanceCriteria": ["Criterion 1", "Criterion 2"],
|
|
174
|
+
"priority": 1,
|
|
175
|
+
"effort": "low|medium|high",
|
|
176
|
+
"passes": false
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Phase 5: IMPLEMENT
|
|
185
|
+
|
|
186
|
+
Hand off to Product Loop:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
/product-loop
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The product loop will:
|
|
193
|
+
1. Read `prd.json` generated by learning system
|
|
194
|
+
2. Execute tasks with circuit breaker protection
|
|
195
|
+
3. Checkpoint before risky changes
|
|
196
|
+
4. Track progress
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## AUTO Mode
|
|
201
|
+
|
|
202
|
+
When `/learn auto` is invoked:
|
|
203
|
+
|
|
204
|
+
1. Scan the codebase to detect technologies and patterns
|
|
205
|
+
2. Identify improvement areas automatically
|
|
206
|
+
3. Generate research topics based on findings
|
|
207
|
+
4. Research each topic (limit: 3 topics)
|
|
208
|
+
5. Continue with analyze → compare → plan
|
|
209
|
+
|
|
210
|
+
### Auto Mode Output
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
Project Profile:
|
|
214
|
+
- Languages: Python, TypeScript
|
|
215
|
+
- Frameworks: FastAPI, React
|
|
216
|
+
- Patterns: Repository Pattern, React Hooks
|
|
217
|
+
- Improvements: add-caching, optimize-queries
|
|
218
|
+
- Topics: FastAPI caching best practices, React performance
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## State Files
|
|
58
224
|
|
|
59
225
|
| File | Purpose |
|
|
60
226
|
|------|---------|
|
|
61
|
-
| `
|
|
227
|
+
| `sources.json` | Research sources config |
|
|
228
|
+
| `research/*.md` | Raw research notes |
|
|
62
229
|
| `insights/patterns.md` | Extracted patterns |
|
|
63
|
-
| `
|
|
230
|
+
| `insights/gap-analysis.md` | Gap analysis |
|
|
231
|
+
| `prd.json` | Generated improvement plan |
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Context Budget
|
|
236
|
+
|
|
237
|
+
This skill is context-aware:
|
|
238
|
+
- Estimates token usage before reading files
|
|
239
|
+
- Warns when approaching budget limits
|
|
240
|
+
- Suggests summarization when needed
|
|
241
|
+
|
|
242
|
+
Check budget: Read `.claude/context_budget.json`
|
|
64
243
|
"""
|
|
65
244
|
_write_file(skill_dir / "SKILL.md", content, force)
|
|
66
245
|
|
|
@@ -68,9 +247,27 @@ RESEARCH → ANALYZE → COMPARE → PLAN
|
|
|
68
247
|
def _create_sources_json(skill_dir: Path, force: bool) -> None:
|
|
69
248
|
"""Create sources.json config."""
|
|
70
249
|
content = """{
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
250
|
+
"version": "1.0",
|
|
251
|
+
"updated": "",
|
|
252
|
+
"projects": [
|
|
253
|
+
{
|
|
254
|
+
"name": "example-project",
|
|
255
|
+
"repo": "owner/repo",
|
|
256
|
+
"category": "reference",
|
|
257
|
+
"topics": ["topic1", "topic2"],
|
|
258
|
+
"docs_url": "https://docs.example.com/"
|
|
259
|
+
}
|
|
260
|
+
],
|
|
261
|
+
"blogs": [
|
|
262
|
+
{
|
|
263
|
+
"name": "Example Blog",
|
|
264
|
+
"url": "https://blog.example.com/",
|
|
265
|
+
"topics": ["topic1", "topic2"]
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
"research_topics": [
|
|
269
|
+
"Add topics relevant to your project"
|
|
270
|
+
]
|
|
74
271
|
}
|
|
75
272
|
"""
|
|
76
273
|
_write_file(skill_dir / "sources.json", content, force)
|
|
@@ -78,16 +275,372 @@ def _create_sources_json(skill_dir: Path, force: bool) -> None:
|
|
|
78
275
|
|
|
79
276
|
def _create_patterns_md(skill_dir: Path, force: bool) -> None:
|
|
80
277
|
"""Create patterns template."""
|
|
81
|
-
|
|
278
|
+
today = date.today().isoformat()
|
|
279
|
+
content = f"""# Extracted Patterns
|
|
82
280
|
|
|
281
|
+
**Created**: {today}
|
|
282
|
+
**Updated**: {today}
|
|
83
283
|
**Status**: 🔄 Active
|
|
84
284
|
|
|
85
285
|
---
|
|
86
286
|
|
|
287
|
+
## How to Use
|
|
288
|
+
|
|
289
|
+
Add patterns discovered during research phases.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
87
293
|
## Pattern Template
|
|
88
294
|
|
|
295
|
+
### Pattern: [Name]
|
|
296
|
+
|
|
89
297
|
- **Source**: Project/Blog
|
|
298
|
+
- **Category**: Architecture | Design | Performance | Security
|
|
90
299
|
- **Description**: What it does
|
|
91
|
-
- **
|
|
300
|
+
- **Implementation**: How it works
|
|
301
|
+
- **Applicability**: How we can use it
|
|
302
|
+
- **Trade-offs**: Pros and cons
|
|
303
|
+
|
|
304
|
+
### Code Example
|
|
305
|
+
|
|
306
|
+
```language
|
|
307
|
+
// Example implementation
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Patterns
|
|
313
|
+
|
|
314
|
+
*Add patterns below this line*
|
|
315
|
+
|
|
316
|
+
---
|
|
92
317
|
"""
|
|
93
318
|
_write_file(skill_dir / "insights/patterns.md", content, force)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _create_gap_analysis_md(skill_dir: Path, force: bool) -> None:
|
|
322
|
+
"""Create gap analysis template."""
|
|
323
|
+
today = date.today().isoformat()
|
|
324
|
+
content = f"""# Gap Analysis
|
|
325
|
+
|
|
326
|
+
**Created**: {today}
|
|
327
|
+
**Updated**: {today}
|
|
328
|
+
**Status**: 🔄 Active
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Summary
|
|
333
|
+
|
|
334
|
+
| Impact | Count | Description |
|
|
335
|
+
|--------|-------|-------------|
|
|
336
|
+
| 🔴 High | 0 | Critical gaps |
|
|
337
|
+
| 🟡 Medium | 0 | Important gaps |
|
|
338
|
+
| 🟢 Low | 0 | Nice-to-have |
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Gap Template
|
|
343
|
+
|
|
344
|
+
### Gap: [Name]
|
|
345
|
+
|
|
346
|
+
- **Current State**: What we have now
|
|
347
|
+
- **Best Practice**: What leading projects do
|
|
348
|
+
- **Impact**: 🔴 High | 🟡 Medium | 🟢 Low
|
|
349
|
+
- **Effort**: Low | Medium | High
|
|
350
|
+
- **Recommendation**: What to do
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Identified Gaps
|
|
355
|
+
|
|
356
|
+
*Add gaps below this line*
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
"""
|
|
360
|
+
_write_file(skill_dir / "insights/gap-analysis.md", content, force)
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def _create_project_analyzer(skill_dir: Path, force: bool) -> None:
|
|
364
|
+
"""Create project analyzer script."""
|
|
365
|
+
content = '''#!/usr/bin/env python3
|
|
366
|
+
"""
|
|
367
|
+
Project Analyzer - Automatically identifies improvement areas in the codebase.
|
|
368
|
+
|
|
369
|
+
Usage:
|
|
370
|
+
python project_analyzer.py [--workspace /path/to/project]
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
import json
|
|
374
|
+
import os
|
|
375
|
+
import re
|
|
376
|
+
from dataclasses import dataclass, field
|
|
377
|
+
from pathlib import Path
|
|
378
|
+
from typing import Optional
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@dataclass
|
|
382
|
+
class ProjectProfile:
|
|
383
|
+
"""Profile of the current project."""
|
|
384
|
+
name: str
|
|
385
|
+
languages: list[str] = field(default_factory=list)
|
|
386
|
+
frameworks: list[str] = field(default_factory=list)
|
|
387
|
+
patterns_detected: list[str] = field(default_factory=list)
|
|
388
|
+
improvement_areas: list[str] = field(default_factory=list)
|
|
389
|
+
research_topics: list[str] = field(default_factory=list)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class ProjectAnalyzer:
|
|
393
|
+
"""Analyzes project to identify improvement opportunities."""
|
|
394
|
+
|
|
395
|
+
# File extension to language mapping
|
|
396
|
+
EXTENSIONS = {
|
|
397
|
+
".py": "Python",
|
|
398
|
+
".js": "JavaScript",
|
|
399
|
+
".ts": "TypeScript",
|
|
400
|
+
".tsx": "TypeScript",
|
|
401
|
+
".jsx": "JavaScript",
|
|
402
|
+
".go": "Go",
|
|
403
|
+
".rs": "Rust",
|
|
404
|
+
".java": "Java",
|
|
405
|
+
".rb": "Ruby",
|
|
406
|
+
".php": "PHP",
|
|
407
|
+
".swift": "Swift",
|
|
408
|
+
".kt": "Kotlin",
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
# Framework indicators
|
|
412
|
+
FRAMEWORK_INDICATORS = {
|
|
413
|
+
# Python
|
|
414
|
+
"fastapi": "FastAPI",
|
|
415
|
+
"django": "Django",
|
|
416
|
+
"flask": "Flask",
|
|
417
|
+
"langchain": "LangChain",
|
|
418
|
+
"langgraph": "LangGraph",
|
|
419
|
+
"pytest": "pytest",
|
|
420
|
+
"sqlalchemy": "SQLAlchemy",
|
|
421
|
+
# JavaScript/TypeScript
|
|
422
|
+
"react": "React",
|
|
423
|
+
"next": "Next.js",
|
|
424
|
+
"vue": "Vue.js",
|
|
425
|
+
"express": "Express",
|
|
426
|
+
"nestjs": "NestJS",
|
|
427
|
+
# Others
|
|
428
|
+
"spring": "Spring",
|
|
429
|
+
"rails": "Rails",
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
# Pattern indicators (regex patterns)
|
|
433
|
+
PATTERN_INDICATORS = {
|
|
434
|
+
r"class.*Repository": "Repository Pattern",
|
|
435
|
+
r"class.*Factory": "Factory Pattern",
|
|
436
|
+
r"class.*Service": "Service Layer",
|
|
437
|
+
r"@dataclass": "Dataclasses",
|
|
438
|
+
r"class.*Protocol": "Protocol Pattern",
|
|
439
|
+
r"async def": "Async/Await",
|
|
440
|
+
r"useEffect|useState": "React Hooks",
|
|
441
|
+
r"def test_": "Unit Tests",
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
def __init__(self, workspace: Optional[Path] = None):
|
|
445
|
+
self.workspace = workspace or Path.cwd()
|
|
446
|
+
|
|
447
|
+
def analyze(self) -> ProjectProfile:
|
|
448
|
+
"""Analyze the project and return a profile."""
|
|
449
|
+
profile = ProjectProfile(name=self.workspace.name)
|
|
450
|
+
|
|
451
|
+
profile.languages = self._detect_languages()
|
|
452
|
+
profile.frameworks = self._detect_frameworks()
|
|
453
|
+
profile.patterns_detected = self._detect_patterns()
|
|
454
|
+
profile.improvement_areas = self._identify_improvements(profile)
|
|
455
|
+
profile.research_topics = self._generate_topics(profile)
|
|
456
|
+
|
|
457
|
+
return profile
|
|
458
|
+
|
|
459
|
+
def _detect_languages(self) -> list[str]:
|
|
460
|
+
"""Detect programming languages in the project."""
|
|
461
|
+
found = set()
|
|
462
|
+
skip_dirs = {".git", "node_modules", "__pycache__", ".venv", "venv", "build", "dist"}
|
|
463
|
+
|
|
464
|
+
for root, dirs, files in os.walk(self.workspace):
|
|
465
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs]
|
|
466
|
+
|
|
467
|
+
for f in files:
|
|
468
|
+
ext = Path(f).suffix.lower()
|
|
469
|
+
if ext in self.EXTENSIONS:
|
|
470
|
+
found.add(self.EXTENSIONS[ext])
|
|
471
|
+
|
|
472
|
+
return sorted(found)
|
|
473
|
+
|
|
474
|
+
def _detect_frameworks(self) -> list[str]:
|
|
475
|
+
"""Detect frameworks and tools in use."""
|
|
476
|
+
frameworks = []
|
|
477
|
+
|
|
478
|
+
# Check common config files
|
|
479
|
+
config_files = [
|
|
480
|
+
self.workspace / "pyproject.toml",
|
|
481
|
+
self.workspace / "requirements.txt",
|
|
482
|
+
self.workspace / "package.json",
|
|
483
|
+
self.workspace / "Cargo.toml",
|
|
484
|
+
self.workspace / "go.mod",
|
|
485
|
+
]
|
|
486
|
+
|
|
487
|
+
for config in config_files:
|
|
488
|
+
if config.exists():
|
|
489
|
+
try:
|
|
490
|
+
content = config.read_text().lower()
|
|
491
|
+
for key, name in self.FRAMEWORK_INDICATORS.items():
|
|
492
|
+
if key in content:
|
|
493
|
+
frameworks.append(name)
|
|
494
|
+
except Exception:
|
|
495
|
+
pass
|
|
496
|
+
|
|
497
|
+
return list(set(frameworks))
|
|
498
|
+
|
|
499
|
+
def _detect_patterns(self) -> list[str]:
|
|
500
|
+
"""Detect code patterns in use."""
|
|
501
|
+
patterns = set()
|
|
502
|
+
skip_dirs = {".git", "node_modules", "__pycache__", ".venv"}
|
|
503
|
+
|
|
504
|
+
src_dir = self.workspace / "src"
|
|
505
|
+
if not src_dir.exists():
|
|
506
|
+
src_dir = self.workspace
|
|
507
|
+
|
|
508
|
+
code_extensions = {".py", ".js", ".ts", ".tsx", ".jsx", ".go", ".rs", ".java"}
|
|
509
|
+
|
|
510
|
+
for root, dirs, files in os.walk(src_dir):
|
|
511
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs]
|
|
512
|
+
|
|
513
|
+
for f in files:
|
|
514
|
+
if Path(f).suffix.lower() not in code_extensions:
|
|
515
|
+
continue
|
|
516
|
+
|
|
517
|
+
filepath = Path(root) / f
|
|
518
|
+
try:
|
|
519
|
+
content = filepath.read_text()
|
|
520
|
+
for pattern, name in self.PATTERN_INDICATORS.items():
|
|
521
|
+
if re.search(pattern, content, re.IGNORECASE):
|
|
522
|
+
patterns.add(name)
|
|
523
|
+
except Exception:
|
|
524
|
+
continue
|
|
525
|
+
|
|
526
|
+
return sorted(patterns)
|
|
527
|
+
|
|
528
|
+
def _identify_improvements(self, profile: ProjectProfile) -> list[str]:
|
|
529
|
+
"""Identify areas that could be improved."""
|
|
530
|
+
improvements = []
|
|
531
|
+
|
|
532
|
+
# Check for missing patterns
|
|
533
|
+
if "Python" in profile.languages:
|
|
534
|
+
if "Unit Tests" not in profile.patterns_detected:
|
|
535
|
+
improvements.append("add-unit-tests")
|
|
536
|
+
if "Protocol Pattern" not in profile.patterns_detected:
|
|
537
|
+
improvements.append("add-interfaces")
|
|
538
|
+
|
|
539
|
+
if "TypeScript" in profile.languages:
|
|
540
|
+
if "Unit Tests" not in profile.patterns_detected:
|
|
541
|
+
improvements.append("add-unit-tests")
|
|
542
|
+
|
|
543
|
+
# Check for optimization opportunities
|
|
544
|
+
if any(f in profile.frameworks for f in ["FastAPI", "Django", "Flask"]):
|
|
545
|
+
improvements.append("add-caching")
|
|
546
|
+
improvements.append("optimize-queries")
|
|
547
|
+
|
|
548
|
+
if "React" in profile.frameworks:
|
|
549
|
+
improvements.append("optimize-renders")
|
|
550
|
+
|
|
551
|
+
return list(set(improvements))
|
|
552
|
+
|
|
553
|
+
def _generate_topics(self, profile: ProjectProfile) -> list[str]:
|
|
554
|
+
"""Generate research topics based on profile."""
|
|
555
|
+
topics = []
|
|
556
|
+
|
|
557
|
+
# Map improvements to research topics
|
|
558
|
+
topic_map = {
|
|
559
|
+
"add-unit-tests": "testing best practices",
|
|
560
|
+
"add-interfaces": "Python Protocol and ABC patterns",
|
|
561
|
+
"add-caching": "caching strategies",
|
|
562
|
+
"optimize-queries": "database query optimization",
|
|
563
|
+
"optimize-renders": "React performance optimization",
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
for improvement in profile.improvement_areas:
|
|
567
|
+
if improvement in topic_map:
|
|
568
|
+
topics.append(topic_map[improvement])
|
|
569
|
+
|
|
570
|
+
# Add framework-specific topics
|
|
571
|
+
for framework in profile.frameworks[:2]: # Limit to 2
|
|
572
|
+
topics.append(f"{framework} best practices")
|
|
573
|
+
|
|
574
|
+
return topics[:5] # Limit to 5 topics
|
|
575
|
+
|
|
576
|
+
def save_profile(self, profile: ProjectProfile) -> Path:
|
|
577
|
+
"""Save profile to JSON file."""
|
|
578
|
+
filepath = self.workspace / ".claude/skills/learning-system/project_profile.json"
|
|
579
|
+
filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
580
|
+
|
|
581
|
+
data = {
|
|
582
|
+
"name": profile.name,
|
|
583
|
+
"languages": profile.languages,
|
|
584
|
+
"frameworks": profile.frameworks,
|
|
585
|
+
"patterns_detected": profile.patterns_detected,
|
|
586
|
+
"improvement_areas": profile.improvement_areas,
|
|
587
|
+
"research_topics": profile.research_topics,
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
filepath.write_text(json.dumps(data, indent=2))
|
|
591
|
+
return filepath
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
def main():
|
|
595
|
+
import sys
|
|
596
|
+
|
|
597
|
+
workspace = None
|
|
598
|
+
if len(sys.argv) > 2 and sys.argv[1] == "--workspace":
|
|
599
|
+
workspace = Path(sys.argv[2])
|
|
600
|
+
|
|
601
|
+
analyzer = ProjectAnalyzer(workspace)
|
|
602
|
+
profile = analyzer.analyze()
|
|
603
|
+
|
|
604
|
+
print(f"Project: {profile.name}")
|
|
605
|
+
print(f"Languages: {', '.join(profile.languages) or 'None detected'}")
|
|
606
|
+
print(f"Frameworks: {', '.join(profile.frameworks) or 'None detected'}")
|
|
607
|
+
print(f"Patterns: {', '.join(profile.patterns_detected) or 'None detected'}")
|
|
608
|
+
print(f"Improvements: {', '.join(profile.improvement_areas) or 'None identified'}")
|
|
609
|
+
print(f"Topics: {', '.join(profile.research_topics) or 'None generated'}")
|
|
610
|
+
|
|
611
|
+
# Save profile
|
|
612
|
+
path = analyzer.save_profile(profile)
|
|
613
|
+
print(f"\\nProfile saved to: {path}")
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
if __name__ == "__main__":
|
|
617
|
+
main()
|
|
618
|
+
'''
|
|
619
|
+
_write_file(skill_dir / "project_analyzer.py", content, force)
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def _create_prd_template(skill_dir: Path, force: bool) -> None:
|
|
623
|
+
"""Create PRD template file."""
|
|
624
|
+
content = """{
|
|
625
|
+
"project": "Project Improvements",
|
|
626
|
+
"branchName": "feature/improvements",
|
|
627
|
+
"description": "Improvements identified by learning system",
|
|
628
|
+
"createdAt": "",
|
|
629
|
+
"userStories": [
|
|
630
|
+
{
|
|
631
|
+
"id": "US-001",
|
|
632
|
+
"title": "Example User Story",
|
|
633
|
+
"description": "As a developer, I want X so that Y",
|
|
634
|
+
"acceptanceCriteria": [
|
|
635
|
+
"Criterion 1",
|
|
636
|
+
"Criterion 2"
|
|
637
|
+
],
|
|
638
|
+
"priority": 1,
|
|
639
|
+
"effort": "medium",
|
|
640
|
+
"passes": false,
|
|
641
|
+
"notes": ""
|
|
642
|
+
}
|
|
643
|
+
]
|
|
644
|
+
}
|
|
645
|
+
"""
|
|
646
|
+
_write_file(skill_dir / "prd_template.json", content, force)
|