scip-cli 1.3.0__tar.gz → 2.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.
- scip_cli-2.1.0/.cursor/rules/agent.mdc +165 -0
- scip_cli-2.1.0/.gitignore +53 -0
- scip_cli-2.1.0/.pre-commit-config.yaml +15 -0
- {scip_cli-1.3.0/scip_cli.egg-info → scip_cli-2.1.0}/PKG-INFO +101 -45
- scip_cli-1.3.0/PKG-INFO → scip_cli-2.1.0/README.md +92 -56
- scip_cli-2.1.0/pyproject.toml +59 -0
- scip_cli-2.1.0/scip_cli/SKILL.md +137 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/__init__.py +2 -1
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/__main__.py +75 -28
- scip_cli-2.1.0/scip_cli/analyze/__init__.py +1 -0
- scip_cli-2.1.0/scip_cli/analyze/common.py +110 -0
- scip_cli-2.1.0/scip_cli/analyze/file.py +354 -0
- scip_cli-2.1.0/scip_cli/analyze/graph.py +130 -0
- scip_cli-2.1.0/scip_cli/analyze/project.py +403 -0
- scip_cli-2.1.0/scip_cli/analyze/sections.py +77 -0
- scip_cli-2.1.0/scip_cli/analyze/symbol.py +184 -0
- scip_cli-2.1.0/scip_cli/analyze/targets.py +97 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/cache.py +28 -5
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/cli_args.py +26 -1
- scip_cli-2.1.0/scip_cli/commands/analyze.py +142 -0
- scip_cli-2.1.0/scip_cli/commands/code.py +123 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/commands/members.py +13 -14
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/commands/rdeps.py +5 -13
- scip_cli-2.1.0/scip_cli/commands/refs.py +166 -0
- scip_cli-2.1.0/scip_cli/commands/reindex.py +69 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/commands/search.py +98 -57
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/commands/skill.py +7 -3
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/commands/symbols.py +4 -6
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/config.py +3 -3
- scip_cli-2.1.0/scip_cli/debug.py +10 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/discover.py +14 -21
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/indexing.py +224 -74
- scip_cli-2.1.0/scip_cli/merge.py +108 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/output.py +56 -26
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/paths.py +37 -3
- scip_cli-2.1.0/scip_cli/project.py +42 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/queries.py +86 -75
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/scip_tool.py +25 -10
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/scope.py +1 -6
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/session.py +2 -1
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/source.py +12 -3
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/sql.py +7 -4
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/symbols.py +39 -12
- scip_cli-2.1.0/scip_cli/targets.py +17 -0
- scip_cli-2.1.0/scripts/build.sh +13 -0
- scip_cli-2.1.0/scripts/publish.sh +32 -0
- scip_cli-2.1.0/scripts/test.sh +9 -0
- scip_cli-2.1.0/tests/analyze_db.py +204 -0
- scip_cli-2.1.0/tests/conftest.py +25 -0
- scip_cli-2.1.0/tests/e2e_harness.py +101 -0
- scip_cli-2.1.0/tests/fixture_catalog.py +17 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/package.json +5 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/app/handler.ts +3 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/config.ts +1 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/consumer.ts +4 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/dead.ts +1 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/helper.ts +7 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/index.ts +3 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/user.ts +6 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/src/widget.ts +7 -0
- scip_cli-2.1.0/tests/fixtures/sample-project/tsconfig.json +8 -0
- scip_cli-2.1.0/tests/perf_util.py +45 -0
- scip_cli-2.1.0/tests/test_analyze.py +223 -0
- scip_cli-2.1.0/tests/test_analyze_graph.py +30 -0
- scip_cli-2.1.0/tests/test_analyze_perf.py +39 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_cache.py +2 -2
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_composability.py +44 -49
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_config.py +1 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_discover.py +1 -0
- scip_cli-2.1.0/tests/test_e2e.py +174 -0
- scip_cli-2.1.0/tests/test_e2e_perf.py +53 -0
- scip_cli-2.1.0/tests/test_index_prune.py +122 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_indexer_env.py +2 -1
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_merge.py +40 -21
- scip_cli-2.1.0/tests/test_multi_symbol.py +205 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_pure_functions.py +277 -270
- scip_cli-2.1.0/tests/test_qualified_symbols.py +100 -0
- scip_cli-2.1.0/tests/test_reindex.py +53 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_scip_tool.py +1 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_scope.py +7 -6
- scip_cli-2.1.0/tests/test_targets.py +17 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/tests/test_typescript_projects.py +1 -0
- scip_cli-1.3.0/MANIFEST.in +0 -4
- scip_cli-1.3.0/README.md +0 -257
- scip_cli-1.3.0/pyproject.toml +0 -13
- scip_cli-1.3.0/scip_cli/SKILL.md +0 -108
- scip_cli-1.3.0/scip_cli/commands/def_cmd.py +0 -57
- scip_cli-1.3.0/scip_cli/commands/refs.py +0 -136
- scip_cli-1.3.0/scip_cli/commands/reindex.py +0 -55
- scip_cli-1.3.0/scip_cli/constants.py +0 -14
- scip_cli-1.3.0/scip_cli/lib.py +0 -64
- scip_cli-1.3.0/scip_cli/merge.py +0 -175
- scip_cli-1.3.0/scip_cli/project.py +0 -29
- scip_cli-1.3.0/scip_cli.egg-info/SOURCES.txt +0 -51
- scip_cli-1.3.0/scip_cli.egg-info/entry_points.txt +0 -2
- scip_cli-1.3.0/scip_cli.egg-info/top_level.txt +0 -1
- scip_cli-1.3.0/setup.cfg +0 -4
- scip_cli-1.3.0/setup.py +0 -37
- scip_cli-1.3.0/tests/test_smoke_cli.py +0 -157
- {scip_cli-1.3.0 → scip_cli-2.1.0}/LICENSE +0 -0
- {scip_cli-1.3.0 → scip_cli-2.1.0}/scip_cli/commands/__init__.py +0 -0
- /scip_cli-1.3.0/scip_cli.egg-info/dependency_links.txt → /scip_cli-2.1.0/tests/__init__.py +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: scip-cli dev workflow and TDD with the shared fixture
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# scip-cli agent
|
|
7
|
+
|
|
8
|
+
**Work from repo root.** CLI usage, flags, and user gotchas: `scip-cli skill` (source: `scip_cli/SKILL.md`). Read once per task — do not duplicate SKILL here.
|
|
9
|
+
|
|
10
|
+
**Almost always:** bare `scip-cli` on PATH must be **this checkout live** (`pip install -e ".[dev]"`). All examples use `scip-cli` — never `.venv/bin/scip-cli`, `python -m scip_cli`, or other paths. Only swap to PyPI briefly to smoke-test a release.
|
|
11
|
+
|
|
12
|
+
## Bootstrap
|
|
13
|
+
|
|
14
|
+
From repo root — keep this mapping for the whole dev session:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -e ".[dev]"
|
|
18
|
+
scip-cli --version # must match scip_cli/__init__.py
|
|
19
|
+
pre-commit install
|
|
20
|
+
scip-cli skill ~/.claude/skills/scip-cli/
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
After publishing: `pip install scip-cli` → smoke-test → `pip install -e ".[dev]"` to restore local.
|
|
24
|
+
|
|
25
|
+
Optional venv for isolation only: create/activate, then same `pip install -e ".[dev]"` — `scip-cli` still runs from PATH, not a venv-relative path.
|
|
26
|
+
|
|
27
|
+
Node.js + `npx` required for integration tests (`scip-typescript`). Optional: `SCIP_CLI_DEBUG=1` (SQL to stderr, truncated).
|
|
28
|
+
|
|
29
|
+
## Lint / test
|
|
30
|
+
|
|
31
|
+
| Task | Command |
|
|
32
|
+
|------|---------|
|
|
33
|
+
| Full suite | `pytest` |
|
|
34
|
+
| E2e loop | `pytest tests/test_e2e.py` |
|
|
35
|
+
| Lint / format | `ruff check .` / `ruff format .` |
|
|
36
|
+
|
|
37
|
+
Pre-commit: ruff + ruff-format + full pytest. E2e before commit on command changes.
|
|
38
|
+
|
|
39
|
+
## Improving this repo (do this before review subagents)
|
|
40
|
+
|
|
41
|
+
**Dogfood on the repo itself** — faster and more honest than spawning reviewers:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
scip-cli reindex
|
|
45
|
+
scip-cli analyze --limit 25
|
|
46
|
+
scip-cli analyze --priority high --limit 25 # dead code & cycles only
|
|
47
|
+
scip-cli analyze scip_cli --limit 15 # directory
|
|
48
|
+
scip-cli analyze scip_cli/queries.py --limit 20 # file (+ scoped project)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Interpretation: README § *Finding easy wins with analyze*. Target = omit (project), directory, file, or symbol — not `--path` for scope.
|
|
52
|
+
|
|
53
|
+
| Priority | Section | Action |
|
|
54
|
+
|----------|---------|--------|
|
|
55
|
+
| 1 | **Cycles** | Break production file dependency cycles (`cache`↔`scope` was one) |
|
|
56
|
+
| 2 | **Unreferenced / dead exports** | No ref usage / no external refs — verify with `rg`, delete or `_` prefix |
|
|
57
|
+
| 3 | **Same-file only** | Module-private by usage — rename to `_` |
|
|
58
|
+
| 4 | **Stale types** | Low-consumer classes — merge or justify |
|
|
59
|
+
|
|
60
|
+
`analyze` skips test paths by default (`tests/`, `*.test.*`, `*.spec.*`); `--include-tests` to include. Reindex after large edits.
|
|
61
|
+
|
|
62
|
+
Do **not** spawn broad code-review agents until this pass is done (or explain why skipped).
|
|
63
|
+
|
|
64
|
+
## Analyze feedback loop (mandatory)
|
|
65
|
+
|
|
66
|
+
When you or a review subagent finds a repo issue — bug, dead code, cycle, risky hub, stale type, unused import — **stop and ask first:**
|
|
67
|
+
|
|
68
|
+
> *Could our SQLite index have predicted this, and `analyze` just doesn't surface it yet?*
|
|
69
|
+
|
|
70
|
+
If **yes** (the signal is in `documents`, `mentions`, `global_symbols`, `defn_enclosing_ranges`):
|
|
71
|
+
|
|
72
|
+
1. **Extend `analyze` first** — new or tuned SQL check in `scip_cli/analyze/`, priority in `sections.py`, tests in `tests/test_analyze.py` + `analyze_db.py`.
|
|
73
|
+
2. **Dogfood** — `reindex` → confirm the issue appears (or the false positive is filtered).
|
|
74
|
+
3. **Then** fix the production code (or document a known blind spot).
|
|
75
|
+
|
|
76
|
+
Only skip step 1 when the issue is **outside the index** (runtime, CLI UX, docs drift, git, env, concurrency, test harness).
|
|
77
|
+
|
|
78
|
+
### Retrospective: caught manually, SQLite already had it
|
|
79
|
+
|
|
80
|
+
| Issue we hit | Index signal | Analyze today | Gap / next check |
|
|
81
|
+
|--------------|--------------|---------------|------------------|
|
|
82
|
+
| `cache` ↔ `scope` import cycle | cross-file `mentions` edges | `[high] Cycles` | **Caught** — keep dogfooding cycles |
|
|
83
|
+
| Cross-file dead export (`get_refs_for_symbols`) | def with no external `mentions` | `[high] Dead exports` | **Caught** |
|
|
84
|
+
| Same-file-only dead code | def, `role=0` only in def file | `[high] Unreferenced` or `[medium] Same-file only` | **Caught** (since extended) |
|
|
85
|
+
| Same-file helper without `_` (`run_with_fallback`) | same-file `role=0` or none | `[medium] Same-file only` / unreferenced | **Caught** — rename to `_` |
|
|
86
|
+
| Typing-only dataclasses (`ProjectSettings`, `IndexScope`) | type `#` symbol, 0 consumer files | `[high] Stale types` + `stale_type_noise` | **Filtered** — index can't see annotations; document or optional `--types` |
|
|
87
|
+
| `analyze/*` section runners “dead” | no external refs | noise filter in `common.py` | **Filtered** — framework pattern |
|
|
88
|
+
| Unused import | `role=2` mention, no in-file use | `[high] Unused imports` (per file) | **Caught** on file target |
|
|
89
|
+
| Hub before editing (`resolve_symbol`, `queries.py`) | fan-in / consumer count | `[medium] Change surface` / `[low] Hotspots` | **Caught** on file target; project hubs are low tier |
|
|
90
|
+
| Symbol only used from tests | consumers all under `tests/` | `[low] Test-only consumers` | **Partial** — Python index often omits same-file `role=0`; verify with `rg` |
|
|
91
|
+
| Indexer omits same-file Python calls | no `role=0` for in-module use | unreferenced / test-only false positives | **Index gap** — not fixable in SQL alone; demoted test-only to low |
|
|
92
|
+
| Duplicate / parallel helpers | — | — | **Not in index** — `rg`, not analyze |
|
|
93
|
+
|
|
94
|
+
Add new rows to `dogfood.md` when you find another gap; implement the SQL check before the next manual review pass.
|
|
95
|
+
|
|
96
|
+
### Size / complexity checks (assessed — don’t promote to high/medium)
|
|
97
|
+
|
|
98
|
+
SQLite has **line ranges** (`defn_enclosing_ranges`) so LOC is cheap. That does **not** mean “big function” belongs next to dead exports.
|
|
99
|
+
|
|
100
|
+
| Idea | In index? | Verdict |
|
|
101
|
+
|------|-----------|---------|
|
|
102
|
+
| **LOC ≥ N** alone | Yes | **LOW at best** — noisy (`main`, argparse, legitimate parsers). Not a nuke candidate. |
|
|
103
|
+
| **LOC + fan-in** (large hub) | Yes | **Already covered** by `[low] Bottlenecks` (fan-in × fan-out). Add `loc=` to that output if helpful; don’t duplicate as medium. |
|
|
104
|
+
| **LOC + consumers** on file target | Yes | **Change surface** (medium) already sorts by consumers with line ranges — drill there. |
|
|
105
|
+
| **Symbol pressure** | Yes | **Per-symbol** `analyze Foo` shows `loc × fan_in × fan_out`. |
|
|
106
|
+
| **God class / many members** | Yes | Use `members Class` — not analyze. |
|
|
107
|
+
| **File byte size / cyclomatic complexity** | No | Out of scope for SCIP index. |
|
|
108
|
+
| **Fat file (many symbols)** | Yes | Low value; coupling/hotspots approximate module heat. |
|
|
109
|
+
|
|
110
|
+
**Rule:** size-only checks stay **low or file-drill-down**; never high/medium unless paired with a **structural smell** (cycle, dead export, zero production consumers). Prefer enriching existing low-tier lines (e.g. show `loc` on bottlenecks) over a new dashboard section.
|
|
111
|
+
|
|
112
|
+
## SQL / analyze benchmarks
|
|
113
|
+
|
|
114
|
+
The e2e fixture and this repo's own index are **small** — every query looks fast here. That hides blowups on real projects (40MB+ indexes, dense graphs).
|
|
115
|
+
|
|
116
|
+
**Before merging new or heavily changed SQL** (`queries.py`, `analyze/*`):
|
|
117
|
+
|
|
118
|
+
1. Time it against **1–2 existing checks** on a **large cached index** you already have (not the fixture):
|
|
119
|
+
```bash
|
|
120
|
+
python3 -u -c "
|
|
121
|
+
import sqlite3, time, sys
|
|
122
|
+
from pathlib import Path
|
|
123
|
+
sys.path.insert(0, '.')
|
|
124
|
+
from scip_cli.analyze import project as p
|
|
125
|
+
from scip_cli.sql import configure_read_connection
|
|
126
|
+
db_path = Path.home() / '.cache/scip-cli/projects/<project-slug>/index.db'
|
|
127
|
+
db = sqlite3.connect(f'file:{db_path}?mode=ro', uri=True)
|
|
128
|
+
configure_read_connection(db)
|
|
129
|
+
for name, fn in [('hotspots', p.hotspots), ('cycles', p.cycles), ('dead_exports', p.dead_exports)]:
|
|
130
|
+
t = time.perf_counter(); fn(db, limit=25); print(f'{name}: {(time.perf_counter()-t)*1000:.0f}ms')
|
|
131
|
+
"
|
|
132
|
+
```
|
|
133
|
+
2. Flag anything **notably slower** than peers — orders of magnitude or multi-second, not a few ms drift.
|
|
134
|
+
3. Swap in your new/changed check for one of the rows; keep a fast peer (e.g. `hotspots`) and a heavy peer (e.g. `dead_exports`).
|
|
135
|
+
|
|
136
|
+
**In CI:** `tests/test_e2e_perf.py` (whole commands) and `tests/test_analyze_perf.py` (per-check on mini DB) catch gross regressions on the tiny fixture only — they **will not** catch large-repo OOMs. Use the manual benchmark above for that.
|
|
137
|
+
|
|
138
|
+
## TDD
|
|
139
|
+
|
|
140
|
+
1. **Red** — `tests/test_e2e.py` + `fixture_catalog` constants.
|
|
141
|
+
2. **Green** — `scip_cli/commands/*.py`.
|
|
142
|
+
3. **Refactor** — unit tests for pure helpers only.
|
|
143
|
+
|
|
144
|
+
- **E2e** (`cli` fixture): in-process `main()`, TS project indexed once per session — default for behavior.
|
|
145
|
+
- **Unit**: `:memory:` SQLite, `tests/analyze_db.py`, merge/index prune tests.
|
|
146
|
+
- **No subprocess** for CLI tests; no `reindex` in e2e (mutates `~/.cache/scip-cli`).
|
|
147
|
+
- New symbols: extend `tests/fixtures/sample-project/` + `fixture_catalog.py`.
|
|
148
|
+
|
|
149
|
+
## Codebase map (contributors)
|
|
150
|
+
|
|
151
|
+
| Area | Path | Notes |
|
|
152
|
+
|------|------|-------|
|
|
153
|
+
| Commands | `scip_cli/commands/` | Thin; SQL in `queries.py` / `analyze/` |
|
|
154
|
+
| Index build | `scip_cli/indexing.py` | `index.db.next` → promote; flock; `>10` tsconfigs log progress |
|
|
155
|
+
| Variable prune | postprocess + `merge.py` | Omit const/let/var on **COPY**, not DELETE — no `variable` kind |
|
|
156
|
+
| Session | `scip_cli/session.py` | `setup()`, `resolve_one_symbol` (limit 2 for ambiguity) |
|
|
157
|
+
| Analyze filters | `scip_cli/analyze/common.py` | `is_test_path`, `analyze_noise` (`_` helpers) |
|
|
158
|
+
|
|
159
|
+
`todo.md` = tracked work; `dogfood.md` = future ideas only. Wishlist/backlog in `docs/` per workspace rules.
|
|
160
|
+
|
|
161
|
+
## Docs touch points
|
|
162
|
+
|
|
163
|
+
- User install + analyze guide → `README.md`
|
|
164
|
+
- Agent/user CLI reference → `scip_cli/SKILL.md` (must match `__main__.py` flags)
|
|
165
|
+
- After flag changes: update SKILL + README command list; run `scip-cli skill` to verify output
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
|
|
23
|
+
# Virtual environments
|
|
24
|
+
venv/
|
|
25
|
+
ENV/
|
|
26
|
+
env/
|
|
27
|
+
.venv
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
*.swp
|
|
33
|
+
*.swo
|
|
34
|
+
*~
|
|
35
|
+
|
|
36
|
+
# OS
|
|
37
|
+
.DS_Store
|
|
38
|
+
Thumbs.db
|
|
39
|
+
|
|
40
|
+
# Env/secrets
|
|
41
|
+
.env
|
|
42
|
+
|
|
43
|
+
# Pytest
|
|
44
|
+
.pytest_cache/
|
|
45
|
+
|
|
46
|
+
# Project specific
|
|
47
|
+
TODO.md
|
|
48
|
+
todo.md
|
|
49
|
+
dogfood.md
|
|
50
|
+
|
|
51
|
+
# Local-only dev scripts (repo-specific smoke harnesses)
|
|
52
|
+
scripts/deep-smoke.sh
|
|
53
|
+
tmp/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.11.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
- repo: local
|
|
9
|
+
hooks:
|
|
10
|
+
- id: pytest
|
|
11
|
+
name: pytest
|
|
12
|
+
entry: pytest
|
|
13
|
+
language: python
|
|
14
|
+
pass_filenames: false
|
|
15
|
+
always_run: true
|
|
@@ -1,82 +1,86 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scip-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Fast code intelligence via SCIP indexes
|
|
5
|
-
|
|
5
|
+
Project-URL: Homepage, https://github.com/flesler/scip-cli
|
|
6
6
|
Author: Ariel Flesler
|
|
7
7
|
License: MIT
|
|
8
|
-
|
|
8
|
+
License-File: LICENSE
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
12
|
Classifier: Topic :: Software Development :: Code Generators
|
|
12
13
|
Requires-Python: >=3.9
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: build>=1; extra == 'dev'
|
|
16
|
+
Requires-Dist: pre-commit>=4.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
18
|
+
Requires-Dist: ruff>=0.11; extra == 'dev'
|
|
13
19
|
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Dynamic: author
|
|
16
|
-
Dynamic: classifier
|
|
17
|
-
Dynamic: description
|
|
18
|
-
Dynamic: description-content-type
|
|
19
|
-
Dynamic: home-page
|
|
20
|
-
Dynamic: license
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
Dynamic: requires-python
|
|
23
|
-
Dynamic: summary
|
|
24
20
|
|
|
25
21
|
# scip-cli
|
|
26
22
|
|
|
27
23
|
[](https://badge.fury.io/py/scip-cli)
|
|
28
24
|
[](https://opensource.org/licenses/MIT)
|
|
29
25
|
|
|
30
|
-
|
|
26
|
+
Token-efficient code intelligence for AI agents. Precise refs, definitions, and repo health analysis via SCIP indexes — TypeScript/JavaScript and Python.
|
|
27
|
+
|
|
28
|
+
## Why
|
|
29
|
+
|
|
30
|
+
AI agents waste tokens on grep and file scanning. scip-cli gives them precise, type-aware code navigation in milliseconds — and `analyze` surfaces dead code, cycles, and coupling so agents (and humans) can fix real problems fast.
|
|
31
31
|
|
|
32
32
|
## Features
|
|
33
33
|
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
36
|
-
- **
|
|
37
|
-
-
|
|
34
|
+
- **Agent-first**: Install as a skill for Claude Code, Cursor, or any AI agent — precise code navigation without burning context
|
|
35
|
+
- **Token-efficient**: One record per line, stderr for warnings, pipe-friendly output
|
|
36
|
+
- **Fast**: Direct SQLite queries — 10x to 213x faster than alternatives
|
|
37
|
+
- **`analyze`**: Find dead exports, import cycles, stale types, coupling hotspots — actionable health dashboards at project, file, or symbol scope
|
|
38
|
+
- **Auto-indexing**: Indexes on first query, caches in SQLite, zero config
|
|
38
39
|
|
|
39
40
|
## For AI Agents
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
Install as a reusable skill so your agent always knows how to navigate the codebase:
|
|
42
43
|
|
|
43
44
|
```bash
|
|
44
|
-
scip-cli skill
|
|
45
|
+
scip-cli skill ~/.claude/skills/scip-cli/ # Claude Code
|
|
46
|
+
scip-cli skill ~/.cursor/skills/scip-cli/ # Cursor
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
Or
|
|
49
|
+
Or dump the quick reference for one-off use:
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
|
-
scip-cli skill
|
|
52
|
+
scip-cli skill
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
This enables commands like `def`, `refs`, `search`, `symbols`, `rdeps`, and `members` - just ask "where is X?" or "find references to X".
|
|
54
|
-
|
|
55
55
|
## Installation
|
|
56
56
|
|
|
57
57
|
### 1. Install scip-cli
|
|
58
58
|
|
|
59
|
-
**From PyPI
|
|
59
|
+
**From PyPI** (end users):
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
62
|
pip install scip-cli
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
**
|
|
65
|
+
**Local development** — almost always keep bare `scip-cli` mapped to this checkout via editable install. You edit the repo; the CLI you run is live code, not a frozen PyPI copy.
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
git clone https://github.com/flesler/scip-cli.git
|
|
69
68
|
cd scip-cli
|
|
70
|
-
pip install .
|
|
69
|
+
pip install -e ".[dev]"
|
|
70
|
+
scip-cli --version
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
All docs and examples use `scip-cli` (never `.venv/bin/scip-cli` or `python -m scip_cli`). After publishing, briefly `pip install scip-cli` to smoke-test PyPI, then `pip install -e ".[dev]"` again.
|
|
74
|
+
|
|
75
|
+
Optional venv for isolation — activate it, run the same editable install, still invoke `scip-cli` on PATH:
|
|
74
76
|
|
|
75
77
|
```bash
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
python -m venv .venv && source .venv/bin/activate
|
|
79
|
+
pip install -e ".[dev]"
|
|
78
80
|
```
|
|
79
81
|
|
|
82
|
+
Tests and lint: `pytest`, `ruff check .` from the same environment.
|
|
83
|
+
|
|
80
84
|
### 2. Install prerequisites (optional)
|
|
81
85
|
|
|
82
86
|
On **first index**, scip-cli runs language indexers and builds a SQLite cache. You can let it fetch tools on demand, or install them globally ahead of time so the first run does not download via `npx`:
|
|
@@ -125,11 +129,12 @@ scip-cli <command> [arguments]
|
|
|
125
129
|
### Commands
|
|
126
130
|
|
|
127
131
|
- `refs <symbol>` - Find all references to a symbol (`--path` to scope)
|
|
128
|
-
- `
|
|
132
|
+
- `code <symbol>` - Find symbol definition with source code (`--path`, `--max-lines`, `--full`, `--offset`, `--snippet`, `--line-numbers`)
|
|
129
133
|
- `search <pattern>` - Search symbols by name pattern (`--path`)
|
|
130
134
|
- `symbols <file>` - List all symbols in a file (`--path`; bare filename OK)
|
|
131
135
|
- `rdeps <file>` - Find files that depend on a file (`--path`)
|
|
132
136
|
- `members <symbol>` - List members of a class/interface (`--path`)
|
|
137
|
+
- `analyze [target]` - SQL health dashboards (`--limit`, `--priority`, `--include-tests`). No target: project-wide; directory or file path; symbol name. See [Finding easy wins with `analyze`](#finding-easy-wins-with-analyze).
|
|
133
138
|
- `reindex` - Force re-indexing of the current project (`--path` to limit scope; repeatable)
|
|
134
139
|
- `skill [path]` - Install or dump the SKILL.md
|
|
135
140
|
|
|
@@ -140,13 +145,13 @@ scip-cli <command> [arguments]
|
|
|
140
145
|
scip-cli refs greet
|
|
141
146
|
|
|
142
147
|
# Get definition of greet
|
|
143
|
-
scip-cli
|
|
148
|
+
scip-cli code greet
|
|
144
149
|
|
|
145
150
|
# Search for symbols matching "Widget"
|
|
146
151
|
scip-cli search Widget
|
|
147
152
|
|
|
148
153
|
# Scope to a subdirectory
|
|
149
|
-
scip-cli
|
|
154
|
+
scip-cli code greet --path packages/api
|
|
150
155
|
|
|
151
156
|
# List symbols by bare filename
|
|
152
157
|
scip-cli symbols helper.ts
|
|
@@ -157,13 +162,16 @@ scip-cli rdeps src/helper.ts
|
|
|
157
162
|
# List members of a class
|
|
158
163
|
scip-cli members Widget
|
|
159
164
|
|
|
165
|
+
# Project health dashboard (or: scip-cli analyze src/foo.ts / scip-cli analyze greet)
|
|
166
|
+
scip-cli analyze
|
|
167
|
+
|
|
160
168
|
# Install skill file
|
|
161
169
|
scip-cli skill ~/.claude/skills/scip-cli/SKILL.md
|
|
162
170
|
```
|
|
163
171
|
|
|
164
172
|
### Pipelines
|
|
165
173
|
|
|
166
|
-
Stdout is one record per line; stderr carries warnings and ambiguity notices. Kinds are lowercase (`function`, `class`, `method`, `property
|
|
174
|
+
Stdout is one record per line; stderr carries warnings and ambiguity notices. Kinds are lowercase (`function`, `class`, `method`, `property`). Pipe-friendly flags: `refs --paths-only`, `search --names-only` / `--paths-only`, `members --names-only`. `rdeps` already prints bare file paths.
|
|
167
175
|
|
|
168
176
|
```bash
|
|
169
177
|
# What do importers of this file export?
|
|
@@ -176,7 +184,7 @@ scip-cli refs greet --paths-only
|
|
|
176
184
|
scip-cli search Handler --kind class --names-only | xargs -I{} scip-cli members {}
|
|
177
185
|
|
|
178
186
|
# Walk class members to their definitions
|
|
179
|
-
scip-cli members Widget --names-only | xargs -I{} scip-cli
|
|
187
|
+
scip-cli members Widget --names-only | xargs -I{} scip-cli code Widget.{}
|
|
180
188
|
```
|
|
181
189
|
|
|
182
190
|
## How It Works
|
|
@@ -206,10 +214,12 @@ Optional `.scip-cli.json` in the project root:
|
|
|
206
214
|
|
|
207
215
|
`SCIP_CLI_INDEX_WORKERS` controls parallel `scip-typescript` runs during first index (default: up to 8). Merge into one database is always serial.
|
|
208
216
|
|
|
217
|
+
Large monorepos (>10 tsconfig projects) log per-project progress to stderr during indexing; smaller repos stay quiet aside from the final `Indexed … (size)` line.
|
|
218
|
+
|
|
209
219
|
Scoped indexing without editing `.scip-cli.json`:
|
|
210
220
|
|
|
211
221
|
```bash
|
|
212
|
-
scip-cli reindex --path
|
|
222
|
+
scip-cli reindex --path packages/server
|
|
213
223
|
scip-cli reindex --path packages/api --path packages/worker
|
|
214
224
|
```
|
|
215
225
|
|
|
@@ -217,20 +227,63 @@ scip-cli reindex --path packages/api --path packages/worker
|
|
|
217
227
|
|
|
218
228
|
Run `scip-cli reindex` after changing scope, `.scip-cli.json` index settings, or when you want a fresh index.
|
|
219
229
|
|
|
220
|
-
|
|
230
|
+
## Finding easy wins with `analyze`
|
|
231
|
+
|
|
232
|
+
Use `analyze` on the repo itself before broad refactors or agent review — it surfaces cross-file issues from the SCIP index (not Python `vulture`).
|
|
233
|
+
|
|
234
|
+
**Quick pass** (after `scip-cli reindex`):
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
scip-cli analyze --limit 25
|
|
238
|
+
scip-cli analyze --priority high --limit 25 # dead exports & cycles only
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Sections are tagged `[high]`, `[medium]`, `[low]` and listed in that order.
|
|
242
|
+
|
|
243
|
+
| Tier | Project sections | Action |
|
|
244
|
+
| ---- | ---------------- | ------ |
|
|
245
|
+
| **high** | Cycles, unreferenced, dead exports, stale types | Nuke or fix cycles; delete unused; `_` prefix |
|
|
246
|
+
| **medium** | Same-file only, change surface (file target) | Module-private by usage |
|
|
247
|
+
| **low** | Test-only consumers, coupling, bottlenecks, hotspots | Noisy on Python (index omits many same-file calls); verify with `rg` |
|
|
248
|
+
|
|
249
|
+
Use `--priority high` for a quick gate; `--priority high,medium` adds context. File drill-down adds change surface and unused imports.
|
|
250
|
+
|
|
251
|
+
**What to look at first**
|
|
252
|
+
|
|
253
|
+
| Section | Easy pickings |
|
|
254
|
+
| ------- | ------------- |
|
|
255
|
+
| **Cycles** | Import/mention cycles between production files — break the edge or extract shared code |
|
|
256
|
+
| **Unreferenced** | No usage in the index at all — delete |
|
|
257
|
+
| **Dead exports** | No external refs — delete or `_` prefix |
|
|
258
|
+
| **Stale types** | Classes/types with ≤1 external consumer — merge, inline, or document why they stay |
|
|
259
|
+
| **Same-file only** | Used only inside defining file — rename to `_` |
|
|
260
|
+
| **Test-only consumers** | Cross-file refs are all from tests — promote to e2e or accept as internal |
|
|
261
|
+
|
|
262
|
+
**Per-file or package drill-down** on hubs or suspects:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
scip-cli analyze scip_cli/queries.py --limit 20 # file: scoped project + per-file + top symbols
|
|
266
|
+
scip-cli analyze scip_cli --limit 15 # directory: scoped project + each file under it
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
`Dead exports in file` lists same-module symbols with no *external* refs — module-private `_helpers` are filtered out. Remaining rows are worth a manual `rg` check.
|
|
270
|
+
|
|
271
|
+
**Defaults:** project-wide and directory analyze skip `tests/`, `*.test.*`, `*.spec.*`, `conftest.py`, and `__tests__/`. Pass `--include-tests` to include them. File-target analyze always includes that file.
|
|
272
|
+
|
|
273
|
+
**Limits:** “Dead export” means no cross-file mentions in the index — not unreachable code. Same-file private helpers are expected. Re-run `reindex` after large changes; the index is a snapshot.
|
|
221
274
|
|
|
222
275
|
## Performance
|
|
223
276
|
|
|
224
|
-
Inspired by [scip-query](https://github.com/PlunderStruck/scip-query), scip-cli is a lightweight Python reimplementation optimized for speed. Compared to the original
|
|
277
|
+
Inspired by [scip-query](https://github.com/PlunderStruck/scip-query), scip-cli is a lightweight Python partial reimplementation optimized for speed. Compared to the original:
|
|
225
278
|
|
|
226
279
|
- `refs`: 6.4s → 0.03s (213x faster)
|
|
227
|
-
- `
|
|
280
|
+
- `code`: 2.8s → 0.05s (56x faster)
|
|
228
281
|
- `search`: 2.6s → 0.03s (87x faster)
|
|
229
282
|
- `symbols`: 0.3s → 0.02s (15x faster)
|
|
230
283
|
- `rdeps`: 0.2s → 0.02s (10x faster)
|
|
231
284
|
- `members`: 3.1s → 0.03s (103x faster)
|
|
232
285
|
|
|
233
|
-
The speedup comes from direct SQLite queries
|
|
286
|
+
The speedup comes from using optimized direct SQLite queries and cutting some nice but very slow goodies (like ts-morph).
|
|
234
287
|
|
|
235
288
|
## Architecture
|
|
236
289
|
|
|
@@ -243,38 +296,41 @@ scip_cli/
|
|
|
243
296
|
├── discover.py # TypeScript project discovery
|
|
244
297
|
├── merge.py # SQLite index merging
|
|
245
298
|
├── scip_tool.py # scip binary download
|
|
246
|
-
├── constants.py # Shared constants
|
|
247
299
|
├── sql.py # SQLite helpers
|
|
248
300
|
├── paths.py # --path scope filtering
|
|
249
301
|
├── project.py # Project root + language detection
|
|
250
302
|
├── cache.py # Index cache paths
|
|
303
|
+
├── scope.py # Persisted reindex scope (index-scope.json)
|
|
304
|
+
├── debug.py # SCIP_CLI_DEBUG stderr helpers
|
|
251
305
|
├── indexing.py # SCIP index build + get_db
|
|
252
306
|
├── symbols.py # Symbol parsing and kinds
|
|
253
307
|
├── queries.py # Symbol/file SQL queries
|
|
254
308
|
├── source.py # Filesystem source reads
|
|
255
309
|
├── output.py # CLI formatting helpers
|
|
256
310
|
├── session.py # setup() and single-match resolution
|
|
311
|
+
├── targets.py # file-path heuristics (tests; analyze uses analyze/targets.py)
|
|
312
|
+
├── analyze/ # SQL dashboard queries (project/file/symbol)
|
|
257
313
|
└── commands/ # Subcommand implementations
|
|
258
314
|
```
|
|
259
315
|
|
|
260
316
|
## Development
|
|
261
317
|
|
|
262
318
|
```bash
|
|
263
|
-
pip install -e .
|
|
319
|
+
pip install -e ".[dev]"
|
|
264
320
|
pytest tests/ -q
|
|
265
321
|
pytest tests/ -m integration -q # indexes tests/fixtures/sample-project (needs scip-typescript)
|
|
266
322
|
```
|
|
267
323
|
|
|
268
324
|
### Debug Logging
|
|
269
325
|
|
|
270
|
-
Set `SCIP_CLI_DEBUG=1` to enable SQL query logging to stderr:
|
|
326
|
+
Set `SCIP_CLI_DEBUG=1` to enable SQL query logging to stderr (statements truncated to 200 chars):
|
|
271
327
|
|
|
272
328
|
```bash
|
|
273
329
|
SCIP_CLI_DEBUG=1 scip-cli refs MyFunction
|
|
274
330
|
# Shows: SQL: SELECT ... | params: (...)
|
|
275
331
|
```
|
|
276
332
|
|
|
277
|
-
This is useful for testing and debugging SQL queries
|
|
333
|
+
This is useful for testing and debugging SQL queries
|
|
278
334
|
|
|
279
335
|
## License
|
|
280
336
|
|