lenspr 0.1.0__tar.gz
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.
- lenspr-0.1.0/.claude/CLAUDE.md +260 -0
- lenspr-0.1.0/.github/workflows/ci.yml +61 -0
- lenspr-0.1.0/.github/workflows/publish.yml +27 -0
- lenspr-0.1.0/.gitignore +46 -0
- lenspr-0.1.0/LICENSE +21 -0
- lenspr-0.1.0/Makefile +304 -0
- lenspr-0.1.0/PKG-INFO +624 -0
- lenspr-0.1.0/README.md +566 -0
- lenspr-0.1.0/assets/demo-bashrc +2 -0
- lenspr-0.1.0/assets/demo-bin/lenspr +2 -0
- lenspr-0.1.0/assets/demo-bin/pip +2 -0
- lenspr-0.1.0/assets/demo-impact.sh +7 -0
- lenspr-0.1.0/assets/demo-output.sh +25 -0
- lenspr-0.1.0/assets/demo-setup.sh +4 -0
- lenspr-0.1.0/assets/demo-shell.sh +2 -0
- lenspr-0.1.0/assets/demo.gif +0 -0
- lenspr-0.1.0/demo.tape +47 -0
- lenspr-0.1.0/docs/ARCHITECTURE.md +107 -0
- lenspr-0.1.0/docs/TOOLS.md +136 -0
- lenspr-0.1.0/lenspr/__init__.py +478 -0
- lenspr-0.1.0/lenspr/architecture.py +265 -0
- lenspr-0.1.0/lenspr/claude_tools.py +111 -0
- lenspr-0.1.0/lenspr/cli.py +1240 -0
- lenspr-0.1.0/lenspr/context.py +504 -0
- lenspr-0.1.0/lenspr/database.py +797 -0
- lenspr-0.1.0/lenspr/doctor.py +535 -0
- lenspr-0.1.0/lenspr/graph.py +351 -0
- lenspr-0.1.0/lenspr/helpers/package-lock.json +31 -0
- lenspr-0.1.0/lenspr/helpers/package.json +16 -0
- lenspr-0.1.0/lenspr/helpers/ts_resolver.js +790 -0
- lenspr-0.1.0/lenspr/mcp_server.py +1378 -0
- lenspr-0.1.0/lenspr/models.py +470 -0
- lenspr-0.1.0/lenspr/monorepo.py +167 -0
- lenspr-0.1.0/lenspr/parsers/__init__.py +54 -0
- lenspr-0.1.0/lenspr/parsers/base.py +161 -0
- lenspr-0.1.0/lenspr/parsers/multi.py +562 -0
- lenspr-0.1.0/lenspr/parsers/node_resolver.py +407 -0
- lenspr-0.1.0/lenspr/parsers/python_parser.py +1009 -0
- lenspr-0.1.0/lenspr/parsers/ts_resolver.py +465 -0
- lenspr-0.1.0/lenspr/parsers/typescript_parser.py +1258 -0
- lenspr-0.1.0/lenspr/patcher.py +257 -0
- lenspr-0.1.0/lenspr/plugins/__init__.py +1 -0
- lenspr-0.1.0/lenspr/prompts/system.md +38 -0
- lenspr-0.1.0/lenspr/pytest_tracer.py +42 -0
- lenspr-0.1.0/lenspr/resolvers/__init__.py +13 -0
- lenspr-0.1.0/lenspr/resolvers/api_mapper.py +776 -0
- lenspr-0.1.0/lenspr/resolvers/ci_mapper.py +501 -0
- lenspr-0.1.0/lenspr/resolvers/config.py +61 -0
- lenspr-0.1.0/lenspr/resolvers/ffi_mapper.py +442 -0
- lenspr-0.1.0/lenspr/resolvers/infra_mapper.py +731 -0
- lenspr-0.1.0/lenspr/resolvers/lsp_client.py +455 -0
- lenspr-0.1.0/lenspr/resolvers/pyright_resolver.py +282 -0
- lenspr-0.1.0/lenspr/resolvers/sql_mapper.py +833 -0
- lenspr-0.1.0/lenspr/resolvers/tsserver_resolver.py +358 -0
- lenspr-0.1.0/lenspr/stats.py +275 -0
- lenspr-0.1.0/lenspr/tool_groups.py +219 -0
- lenspr-0.1.0/lenspr/tools/__init__.py +411 -0
- lenspr-0.1.0/lenspr/tools/analysis.py +651 -0
- lenspr-0.1.0/lenspr/tools/annotation.py +301 -0
- lenspr-0.1.0/lenspr/tools/arch.py +275 -0
- lenspr-0.1.0/lenspr/tools/entry_points.py +487 -0
- lenspr-0.1.0/lenspr/tools/explain.py +466 -0
- lenspr-0.1.0/lenspr/tools/git.py +413 -0
- lenspr-0.1.0/lenspr/tools/helpers.py +180 -0
- lenspr-0.1.0/lenspr/tools/modification.py +844 -0
- lenspr-0.1.0/lenspr/tools/navigation.py +519 -0
- lenspr-0.1.0/lenspr/tools/patterns.py +234 -0
- lenspr-0.1.0/lenspr/tools/resolvers.py +491 -0
- lenspr-0.1.0/lenspr/tools/safety.py +1418 -0
- lenspr-0.1.0/lenspr/tools/schemas.py +1123 -0
- lenspr-0.1.0/lenspr/tools/session.py +230 -0
- lenspr-0.1.0/lenspr/tools/temporal.py +327 -0
- lenspr-0.1.0/lenspr/tools/testing.py +180 -0
- lenspr-0.1.0/lenspr/tools/trace.py +228 -0
- lenspr-0.1.0/lenspr/tracer.py +190 -0
- lenspr-0.1.0/lenspr/tracker.py +125 -0
- lenspr-0.1.0/lenspr/validator.py +195 -0
- lenspr-0.1.0/package-lock.json +26 -0
- lenspr-0.1.0/package.json +5 -0
- lenspr-0.1.0/plan.md +230 -0
- lenspr-0.1.0/pyproject.toml +110 -0
- lenspr-0.1.0/tests/__init__.py +0 -0
- lenspr-0.1.0/tests/fixtures/sample_project/main.py +25 -0
- lenspr-0.1.0/tests/fixtures/sample_project/models.py +26 -0
- lenspr-0.1.0/tests/fixtures/sample_project/utils/__init__.py +0 -0
- lenspr-0.1.0/tests/fixtures/sample_project/utils/helpers.py +22 -0
- lenspr-0.1.0/tests/test_analysis.py +414 -0
- lenspr-0.1.0/tests/test_annotations.py +509 -0
- lenspr-0.1.0/tests/test_api_mapper.py +1284 -0
- lenspr-0.1.0/tests/test_arch_tools.py +231 -0
- lenspr-0.1.0/tests/test_architecture.py +203 -0
- lenspr-0.1.0/tests/test_batch_rollback.py +323 -0
- lenspr-0.1.0/tests/test_ci_mapper.py +501 -0
- lenspr-0.1.0/tests/test_cli.py +117 -0
- lenspr-0.1.0/tests/test_context.py +618 -0
- lenspr-0.1.0/tests/test_database.py +196 -0
- lenspr-0.1.0/tests/test_doctor.py +102 -0
- lenspr-0.1.0/tests/test_entry_points.py +322 -0
- lenspr-0.1.0/tests/test_explain_tools.py +308 -0
- lenspr-0.1.0/tests/test_ffi_mapper.py +401 -0
- lenspr-0.1.0/tests/test_git_tools.py +252 -0
- lenspr-0.1.0/tests/test_graph.py +122 -0
- lenspr-0.1.0/tests/test_helpers.py +230 -0
- lenspr-0.1.0/tests/test_infra_mapper.py +575 -0
- lenspr-0.1.0/tests/test_lsp_client.py +371 -0
- lenspr-0.1.0/tests/test_mcp_server.py +392 -0
- lenspr-0.1.0/tests/test_modification_guards.py +145 -0
- lenspr-0.1.0/tests/test_navigation.py +541 -0
- lenspr-0.1.0/tests/test_parser.py +592 -0
- lenspr-0.1.0/tests/test_patcher.py +163 -0
- lenspr-0.1.0/tests/test_pyright_resolver.py +209 -0
- lenspr-0.1.0/tests/test_safety.py +404 -0
- lenspr-0.1.0/tests/test_session_tools.py +227 -0
- lenspr-0.1.0/tests/test_sql_mapper.py +668 -0
- lenspr-0.1.0/tests/test_tool_groups.py +298 -0
- lenspr-0.1.0/tests/test_tool_operations.py +594 -0
- lenspr-0.1.0/tests/test_tracker.py +176 -0
- lenspr-0.1.0/tests/test_ts_resolver.py +524 -0
- lenspr-0.1.0/tests/test_tsserver_resolver.py +418 -0
- lenspr-0.1.0/tests/test_typescript_parser.py +553 -0
- lenspr-0.1.0/tests/test_validator.py +110 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# LensPR Project Instructions
|
|
2
|
+
|
|
3
|
+
## ⛔ ABSOLUTE REQUIREMENTS — NO EXCEPTIONS
|
|
4
|
+
|
|
5
|
+
**STOP. Before ANY action on Python files (.py), you MUST use lenspr tools FIRST.**
|
|
6
|
+
|
|
7
|
+
This includes:
|
|
8
|
+
- Editing `.py` files → `lens_check_impact` FIRST
|
|
9
|
+
- Deleting `.py` files → `lens_search` + `lens_find_usages` FIRST
|
|
10
|
+
- Moving/renaming `.py` files → `lens_find_usages` FIRST
|
|
11
|
+
- Reading `.py` files → `lens_get_node` or `lens_context` instead of `Read`
|
|
12
|
+
- Searching in `.py` files → `lens_grep` or `lens_search` instead of `Grep`
|
|
13
|
+
|
|
14
|
+
**VIOLATION = IMMEDIATE STOP.** If you catch yourself using Bash `rm`, `mv` on .py files, or using `Grep`/`Read` on Python code — STOP and use lenspr instead.
|
|
15
|
+
|
|
16
|
+
### Mandatory Checklist Before Python File Operations:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
□ Is this a .py file? → USE LENSPR
|
|
20
|
+
□ Am I deleting? → lens_search (is it in graph?) + lens_find_usages (who uses it?)
|
|
21
|
+
□ Am I editing? → lens_check_impact (what breaks?)
|
|
22
|
+
□ Am I reading? → lens_get_node or lens_context (not Read)
|
|
23
|
+
□ Am I searching? → lens_grep or lens_search (not Grep)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Mandatory Checklist After Every Code Change:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
□ After lens_add_node or lens_update_node → run lens_run_tests()
|
|
30
|
+
□ Syntax validation ≠ behavioral correctness
|
|
31
|
+
□ Do not proceed to the next change until tests pass
|
|
32
|
+
□ For NEW functions: also run lens_generate_test_skeleton(node_id) and write tests
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**What `lens_run_tests()` actually catches:** import-time crashes (NameError, missing symbols, broken references between modules). Python resolves imports at load time — `pytest` will fail at collection if the new code references a non-existent function.
|
|
36
|
+
|
|
37
|
+
**What `lens_run_tests()` does NOT catch:** behavioral bugs in the new code itself. Logic errors, wrong return values, unhandled edge cases — none of this is verified without tests that specifically call the new function.
|
|
38
|
+
|
|
39
|
+
**Full verification loop for new code:**
|
|
40
|
+
1. `lens_run_tests()` → no import crashes, no regressions in already-covered code
|
|
41
|
+
2. `lens_generate_test_skeleton(node_id)` → test spec (scenarios, mocks, usage examples)
|
|
42
|
+
3. Write tests based on the spec → behavioral correctness confirmed
|
|
43
|
+
|
|
44
|
+
### Why This Is Non-Negotiable:
|
|
45
|
+
|
|
46
|
+
You have a **proven pattern** of:
|
|
47
|
+
1. Using lenspr once, then forgetting it exists
|
|
48
|
+
2. Falling back to Bash/Grep/Read out of habit
|
|
49
|
+
3. Deleting files without checking dependencies
|
|
50
|
+
4. Making changes without impact analysis
|
|
51
|
+
|
|
52
|
+
**This causes bugs that lenspr was built to prevent.**
|
|
53
|
+
|
|
54
|
+
### Specific Violations To Avoid:
|
|
55
|
+
|
|
56
|
+
❌ **WRONG:** `Read("/Users/.../lenspr/cli.py")` to read Python code
|
|
57
|
+
✅ **RIGHT:** `lens_get_node("lenspr.cli.cmd_init")` or `lens_context("lenspr.cli")`
|
|
58
|
+
|
|
59
|
+
❌ **WRONG:** `Grep(pattern="results_v2", path="lenspr/")` to search Python
|
|
60
|
+
✅ **RIGHT:** `lens_grep("results_v2")` or `lens_search("results_v2", search_in="code")`
|
|
61
|
+
|
|
62
|
+
❌ **WRONG:** Reading full .py file with `Read` then manually finding a function
|
|
63
|
+
✅ **RIGHT:** `lens_get_node("module.function")` returns exact code
|
|
64
|
+
|
|
65
|
+
❌ **WRONG:** "Let me verify the file imports correctly" using `python -c "import ..."`
|
|
66
|
+
✅ **RIGHT:** Trust lenspr — if you edited via `lens_update_node`, it validated syntax
|
|
67
|
+
|
|
68
|
+
❌ **WRONG:** `Bash("rm -f some_file.py")` without checking graph
|
|
69
|
+
✅ **RIGHT:** `lens_search` + `lens_find_usages` FIRST, then delete
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## CRITICAL: READ CODE VS RUN CODE
|
|
74
|
+
|
|
75
|
+
**If you have read 3+ files in a row and everything "looks correct" — STOP. Run the code.**
|
|
76
|
+
|
|
77
|
+
LensPR tools are convenient for reading code but cannot execute it. When debugging runtime behavior (what edges get created, what jedi resolves, what a function actually returns), **running code is 30 seconds, reading code is 25 tool calls**.
|
|
78
|
+
|
|
79
|
+
### The Anti-Pattern (documented from real session, 2026-02-18):
|
|
80
|
+
|
|
81
|
+
**Symptom:** Debugging why `from lenspr import database` creates no graph edges.
|
|
82
|
+
**Wrong approach:** Read `_extract_calls` → looks correct. Read `_ImportTable.resolve` → looks correct. Read `_resolve_edges_with_jedi` → looks correct. Read `normalize_edge_targets` → looks correct. Read `save_graph` → looks correct. (25 tool calls, ~25 minutes, no answer)
|
|
83
|
+
**Right approach:** Run the parser directly:
|
|
84
|
+
```python
|
|
85
|
+
python3 -c "
|
|
86
|
+
from lenspr.parsers.python_parser import CodeGraphVisitor
|
|
87
|
+
import ast
|
|
88
|
+
source = 'from lenspr import database\ndef f():\n database.save_graph(x)'
|
|
89
|
+
visitor = CodeGraphVisitor(source.splitlines(), 'test', 'test.py')
|
|
90
|
+
visitor.visit(ast.parse(source))
|
|
91
|
+
for e in visitor.edges: print(e.from_node, '->', e.to_node, e.confidence.value)
|
|
92
|
+
"
|
|
93
|
+
```
|
|
94
|
+
Result in 30 seconds: edges ARE created. Bug is not in parser. Move to next layer.
|
|
95
|
+
|
|
96
|
+
### Decision Rule:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
□ Debugging runtime behavior? → python3 -c first, THEN read code if needed
|
|
100
|
+
□ Third file looks "correct"? → STOP. Run the thing.
|
|
101
|
+
□ "jedi should return X"? → script.goto() in python3 -c to verify
|
|
102
|
+
□ "edge should be created"? → parse a minimal example, check visitor.edges
|
|
103
|
+
□ "save_graph should save it"? → run parse_project() + inspect edges list
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Root cause:** LensPR is the primary tool → agent stays inside LensPR → LensPR can't execute code → agent reads instead of runs. Bash is available and faster for verification. Use it.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## TRUST THE GRAPH
|
|
111
|
+
|
|
112
|
+
The MCP server has a **file watcher that auto-syncs** the graph before every tool call.
|
|
113
|
+
|
|
114
|
+
**DO:**
|
|
115
|
+
- Call `lens_search` and trust the result
|
|
116
|
+
- Call `lens_check_impact` and trust the result
|
|
117
|
+
- Assume the graph is up-to-date
|
|
118
|
+
|
|
119
|
+
**DON'T:**
|
|
120
|
+
- Call `lens_diff` "just to check" if graph is synced — it's automatic
|
|
121
|
+
- Double-check lenspr results with Grep/Read — trust the graph
|
|
122
|
+
- Say "the graph might not be synced" — it is synced
|
|
123
|
+
- Use `Read` on .py files "to see the full file" — use `lens_get_node` for specific code
|
|
124
|
+
|
|
125
|
+
If lenspr says a function doesn't exist, it doesn't exist. Trust it.
|
|
126
|
+
|
|
127
|
+
**Exception:** Use `Read` on .py files ONLY when you need to rewrite the ENTIRE file with `Write`. Otherwise, always use lenspr.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## CRITICAL: MANDATORY RULES FOR CODE CHANGES
|
|
132
|
+
|
|
133
|
+
**BLOCKING REQUIREMENTS — violations will cause bugs:**
|
|
134
|
+
|
|
135
|
+
1. **BEFORE modifying ANY Python code**, you MUST call `lens_check_impact("node_id")`. No exceptions.
|
|
136
|
+
2. **NEVER use Edit on .py files** without first calling `lens_check_impact`.
|
|
137
|
+
3. **NEVER delete .py files** without first calling `lens_search` + `lens_find_usages`.
|
|
138
|
+
4. **NEVER use Grep on Python code** — use `lens_grep` instead.
|
|
139
|
+
5. **NEVER use Read on Python code** — use `lens_get_node` or `lens_context` instead.
|
|
140
|
+
6. If `lens_check_impact` returns severity CRITICAL or HIGH — warn the user and wait for confirmation.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Code Navigation - USE LENSPR TOOLS
|
|
145
|
+
|
|
146
|
+
This project has LensPR MCP tools available. **ALWAYS prefer lenspr tools over Read/Grep/Glob** for code exploration.
|
|
147
|
+
|
|
148
|
+
### Primary Tool: lens_context
|
|
149
|
+
```
|
|
150
|
+
lens_context("module.Class.method") # Returns: source + callers + callees + tests
|
|
151
|
+
```
|
|
152
|
+
**Use this first.** One call gives you everything needed to understand a function.
|
|
153
|
+
|
|
154
|
+
### Finding Code
|
|
155
|
+
```
|
|
156
|
+
lens_search("function_name") # Find by name
|
|
157
|
+
lens_search("pattern", search_in="code") # Find in code content
|
|
158
|
+
lens_grep("TODO|FIXME") # Regex search with graph context
|
|
159
|
+
lens_list_nodes(type="function") # List all functions
|
|
160
|
+
lens_get_structure(mode="summary") # Project overview (compact)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Understanding Dependencies
|
|
164
|
+
```
|
|
165
|
+
lens_get_connections("node_id") # Direct callers/callees
|
|
166
|
+
lens_find_usages("node_id") # ALL references (callers + importers + inheritors)
|
|
167
|
+
lens_check_impact("node_id", depth=3) # Full impact zone with severity
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Before Modifying Code - REQUIRED
|
|
171
|
+
```
|
|
172
|
+
lens_check_impact("node_id") # ALWAYS check first - shows CRITICAL/HIGH/MEDIUM/LOW
|
|
173
|
+
lens_validate_change("node_id", code) # Dry-run: validates without applying
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Git Integration
|
|
177
|
+
```
|
|
178
|
+
lens_blame("node_id") # Who wrote each line
|
|
179
|
+
lens_node_history("node_id") # Commits that modified this function
|
|
180
|
+
lens_recent_changes(limit=10) # What changed recently
|
|
181
|
+
lens_commit_scope("abc123") # What a specific commit affected
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Code Quality
|
|
185
|
+
```
|
|
186
|
+
lens_health() # Graph confidence %, docstring coverage
|
|
187
|
+
lens_dead_code() # Find unreachable code
|
|
188
|
+
lens_dependencies() # External packages used
|
|
189
|
+
lens_annotation_stats() # Semantic annotation coverage
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Workflow Examples
|
|
193
|
+
|
|
194
|
+
### "What does this function do?"
|
|
195
|
+
```
|
|
196
|
+
lens_context("module.function") # Get code + who calls it + what it calls + tests
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### "I need to change function X"
|
|
200
|
+
```
|
|
201
|
+
1. lens_check_impact("X") # Check severity first
|
|
202
|
+
2. lens_context("X") # Understand the function
|
|
203
|
+
3. lens_validate_change("X", new_code) # Test change
|
|
204
|
+
4. Edit tool to apply # Only after validation passes
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### "Find where errors are handled"
|
|
208
|
+
```
|
|
209
|
+
lens_grep("except|raise", file_glob="*.py") # With graph context
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### "Who wrote this code?"
|
|
213
|
+
```
|
|
214
|
+
lens_blame("module.function") # Git blame per line
|
|
215
|
+
lens_node_history("module.function") # Commit history
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### "Clean up dead code"
|
|
219
|
+
```
|
|
220
|
+
lens_dead_code() # Lists unused functions
|
|
221
|
+
lens_find_usages("suspected_dead") # Verify no callers
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Why LensPR Over Traditional Tools?
|
|
225
|
+
|
|
226
|
+
| Task | Traditional | LensPR | Benefit |
|
|
227
|
+
|------|-------------|--------|---------|
|
|
228
|
+
| Read function | Read file, find function | `lens_get_node` | Exact code only |
|
|
229
|
+
| Understand function | Read + Grep callers + Grep tests | `lens_context` | **One call** |
|
|
230
|
+
| Safe refactoring | Hope for the best | `lens_check_impact` | Know severity |
|
|
231
|
+
| Find usages | Grep (misses dynamic) | `lens_find_usages` | Graph-aware |
|
|
232
|
+
| Code search | Grep | `lens_grep` | Shows containing function |
|
|
233
|
+
|
|
234
|
+
## When to Use Traditional Tools
|
|
235
|
+
|
|
236
|
+
- **Write/Edit** - For actually modifying files
|
|
237
|
+
- **Bash** - For git commits, running tests, shell commands
|
|
238
|
+
- **Read** - For non-Python files (configs, markdown, JSON)
|
|
239
|
+
|
|
240
|
+
## Project Structure
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
lenspr/
|
|
244
|
+
├── parsers/ # Python AST + jedi parser
|
|
245
|
+
├── tools/ # Tool handlers (analysis, navigation, modification)
|
|
246
|
+
├── mcp_server.py # MCP server (27 tools)
|
|
247
|
+
└── validator.py # 3-level code validation
|
|
248
|
+
tests/ # pytest suite
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Development Commands
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
make dev # Install with dev dependencies
|
|
255
|
+
make test # Run tests
|
|
256
|
+
make check # Lint + typecheck + test
|
|
257
|
+
make health # Show graph stats
|
|
258
|
+
make annotations # Show annotation coverage
|
|
259
|
+
make publish # Build and publish to PyPI
|
|
260
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e ".[dev,mcp,watch]"
|
|
28
|
+
|
|
29
|
+
- name: Lint with ruff
|
|
30
|
+
run: ruff check lenspr tests
|
|
31
|
+
|
|
32
|
+
- name: Type check with mypy
|
|
33
|
+
run: mypy lenspr --ignore-missing-imports
|
|
34
|
+
|
|
35
|
+
- name: Run tests
|
|
36
|
+
run: pytest --tb=short -q
|
|
37
|
+
|
|
38
|
+
publish:
|
|
39
|
+
needs: test
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && startsWith(github.event.head_commit.message, 'release:')
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
|
|
46
|
+
- name: Set up Python
|
|
47
|
+
uses: actions/setup-python@v5
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.11"
|
|
50
|
+
|
|
51
|
+
- name: Install build tools
|
|
52
|
+
run: pip install build twine
|
|
53
|
+
|
|
54
|
+
- name: Build package
|
|
55
|
+
run: python -m build
|
|
56
|
+
|
|
57
|
+
- name: Publish to PyPI
|
|
58
|
+
env:
|
|
59
|
+
TWINE_USERNAME: __token__
|
|
60
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
61
|
+
run: twine upload dist/*
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.12"
|
|
19
|
+
|
|
20
|
+
- name: Install build tools
|
|
21
|
+
run: pip install build
|
|
22
|
+
|
|
23
|
+
- name: Build package
|
|
24
|
+
run: python -m build
|
|
25
|
+
|
|
26
|
+
- name: Publish to PyPI
|
|
27
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
lenspr-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.egg
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
*~
|
|
23
|
+
|
|
24
|
+
# Testing
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
|
|
30
|
+
# LensPR generated
|
|
31
|
+
.lens/
|
|
32
|
+
|
|
33
|
+
# MCP config (contains absolute paths)
|
|
34
|
+
.mcp.json
|
|
35
|
+
|
|
36
|
+
# OS
|
|
37
|
+
.DS_Store
|
|
38
|
+
Thumbs.db
|
|
39
|
+
.env
|
|
40
|
+
eval/
|
|
41
|
+
|
|
42
|
+
# Node.js
|
|
43
|
+
node_modules/
|
|
44
|
+
|
|
45
|
+
# Claude Code (temporary files, plans)
|
|
46
|
+
.claude/plans/
|
lenspr-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 kyrylopr
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|