scip-cli 1.2.0__tar.gz → 2.0.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.0.0/.cursor/rules/agent.mdc +133 -0
- scip_cli-2.0.0/.gitignore +53 -0
- scip_cli-2.0.0/.pre-commit-config.yaml +15 -0
- scip_cli-2.0.0/PKG-INFO +330 -0
- scip_cli-2.0.0/README.md +310 -0
- scip_cli-2.0.0/pyproject.toml +59 -0
- scip_cli-2.0.0/scip_cli/SKILL.md +135 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/__init__.py +2 -1
- scip_cli-2.0.0/scip_cli/__main__.py +180 -0
- scip_cli-2.0.0/scip_cli/analyze/__init__.py +1 -0
- scip_cli-2.0.0/scip_cli/analyze/common.py +110 -0
- scip_cli-2.0.0/scip_cli/analyze/file.py +354 -0
- scip_cli-2.0.0/scip_cli/analyze/project.py +435 -0
- scip_cli-2.0.0/scip_cli/analyze/sections.py +77 -0
- scip_cli-2.0.0/scip_cli/analyze/symbol.py +184 -0
- scip_cli-2.0.0/scip_cli/analyze/targets.py +97 -0
- scip_cli-2.0.0/scip_cli/cache.py +93 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/cli_args.py +26 -1
- scip_cli-2.0.0/scip_cli/commands/analyze.py +142 -0
- scip_cli-2.0.0/scip_cli/commands/code.py +123 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/commands/members.py +13 -14
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/commands/rdeps.py +5 -13
- scip_cli-2.0.0/scip_cli/commands/refs.py +166 -0
- scip_cli-2.0.0/scip_cli/commands/reindex.py +69 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/commands/search.py +99 -58
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/commands/skill.py +7 -3
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/commands/symbols.py +4 -6
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/config.py +3 -3
- scip_cli-2.0.0/scip_cli/debug.py +10 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/discover.py +14 -21
- scip_cli-2.0.0/scip_cli/indexing.py +520 -0
- scip_cli-2.0.0/scip_cli/merge.py +108 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/output.py +56 -26
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/paths.py +37 -3
- scip_cli-2.0.0/scip_cli/project.py +42 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/queries.py +86 -75
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/scip_tool.py +25 -10
- scip_cli-2.0.0/scip_cli/scope.py +69 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/session.py +2 -1
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/source.py +12 -3
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/sql.py +7 -4
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/symbols.py +39 -12
- scip_cli-2.0.0/scip_cli/targets.py +17 -0
- scip_cli-2.0.0/scripts/build.sh +13 -0
- scip_cli-2.0.0/scripts/publish.sh +32 -0
- scip_cli-2.0.0/scripts/test.sh +9 -0
- scip_cli-2.0.0/tests/analyze_db.py +204 -0
- scip_cli-2.0.0/tests/conftest.py +25 -0
- scip_cli-2.0.0/tests/e2e_harness.py +101 -0
- scip_cli-2.0.0/tests/fixture_catalog.py +17 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/package.json +5 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/app/handler.ts +3 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/config.ts +1 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/consumer.ts +4 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/dead.ts +1 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/helper.ts +7 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/index.ts +3 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/user.ts +6 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/src/widget.ts +7 -0
- scip_cli-2.0.0/tests/fixtures/sample-project/tsconfig.json +8 -0
- scip_cli-2.0.0/tests/test_analyze.py +223 -0
- scip_cli-2.0.0/tests/test_cache.py +54 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_composability.py +44 -49
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_config.py +1 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_discover.py +1 -0
- scip_cli-2.0.0/tests/test_e2e.py +174 -0
- scip_cli-2.0.0/tests/test_index_prune.py +122 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_indexer_env.py +2 -1
- scip_cli-2.0.0/tests/test_merge.py +227 -0
- scip_cli-2.0.0/tests/test_multi_symbol.py +205 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_pure_functions.py +294 -266
- scip_cli-2.0.0/tests/test_qualified_symbols.py +100 -0
- scip_cli-2.0.0/tests/test_reindex.py +53 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_scip_tool.py +1 -0
- scip_cli-2.0.0/tests/test_scope.py +62 -0
- scip_cli-2.0.0/tests/test_targets.py +17 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/tests/test_typescript_projects.py +1 -0
- scip_cli-1.2.0/MANIFEST.in +0 -4
- scip_cli-1.2.0/PKG-INFO +0 -267
- scip_cli-1.2.0/README.md +0 -243
- scip_cli-1.2.0/pyproject.toml +0 -13
- scip_cli-1.2.0/scip_cli/SKILL.md +0 -108
- scip_cli-1.2.0/scip_cli/__main__.py +0 -127
- scip_cli-1.2.0/scip_cli/cache.py +0 -34
- scip_cli-1.2.0/scip_cli/commands/def_cmd.py +0 -57
- scip_cli-1.2.0/scip_cli/commands/refs.py +0 -136
- scip_cli-1.2.0/scip_cli/commands/reindex.py +0 -28
- scip_cli-1.2.0/scip_cli/constants.py +0 -7
- scip_cli-1.2.0/scip_cli/indexing.py +0 -292
- scip_cli-1.2.0/scip_cli/lib.py +0 -64
- scip_cli-1.2.0/scip_cli/merge.py +0 -174
- scip_cli-1.2.0/scip_cli/project.py +0 -29
- scip_cli-1.2.0/scip_cli.egg-info/PKG-INFO +0 -267
- scip_cli-1.2.0/scip_cli.egg-info/SOURCES.txt +0 -49
- scip_cli-1.2.0/scip_cli.egg-info/entry_points.txt +0 -2
- scip_cli-1.2.0/scip_cli.egg-info/top_level.txt +0 -1
- scip_cli-1.2.0/setup.cfg +0 -4
- scip_cli-1.2.0/setup.py +0 -37
- scip_cli-1.2.0/tests/test_cache.py +0 -22
- scip_cli-1.2.0/tests/test_merge.py +0 -136
- scip_cli-1.2.0/tests/test_smoke_cli.py +0 -157
- {scip_cli-1.2.0 → scip_cli-2.0.0}/LICENSE +0 -0
- {scip_cli-1.2.0 → scip_cli-2.0.0}/scip_cli/commands/__init__.py +0 -0
- /scip_cli-1.2.0/scip_cli.egg-info/dependency_links.txt → /scip_cli-2.0.0/tests/__init__.py +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
Use **`.venv/bin/scip-cli`** / **`.venv/bin/pytest`**. Uncommitted code: `PYTHONPATH=$PWD python -m scip_cli …` if the venv binary is stale.
|
|
11
|
+
|
|
12
|
+
## Bootstrap
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python -m venv .venv && source .venv/bin/activate
|
|
16
|
+
pip install -e ".[dev]"
|
|
17
|
+
pre-commit install
|
|
18
|
+
scip-cli skill
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Node.js + `npx` required for integration tests (`scip-typescript`). Optional: `SCIP_CLI_DEBUG=1` (SQL to stderr, truncated).
|
|
22
|
+
|
|
23
|
+
## Lint / test
|
|
24
|
+
|
|
25
|
+
| Task | Command |
|
|
26
|
+
|------|---------|
|
|
27
|
+
| Full suite | `.venv/bin/pytest` |
|
|
28
|
+
| E2e loop | `.venv/bin/pytest tests/test_e2e.py` |
|
|
29
|
+
| Lint / format | `.venv/bin/ruff check .` / `ruff format .` |
|
|
30
|
+
|
|
31
|
+
Pre-commit: ruff + ruff-format + full pytest. E2e before commit on command changes.
|
|
32
|
+
|
|
33
|
+
## Improving this repo (do this before review subagents)
|
|
34
|
+
|
|
35
|
+
**Dogfood on the repo itself** — faster and more honest than spawning reviewers:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
.venv/bin/scip-cli reindex
|
|
39
|
+
.venv/bin/scip-cli analyze --limit 25
|
|
40
|
+
.venv/bin/scip-cli analyze --priority high --limit 25 # dead code & cycles only
|
|
41
|
+
.venv/bin/scip-cli analyze scip_cli --limit 15 # directory
|
|
42
|
+
.venv/bin/scip-cli analyze scip_cli/queries.py --limit 20 # file (+ scoped project)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Interpretation: README § *Finding easy wins with analyze*. Target = omit (project), directory, file, or symbol — not `--path` for scope.
|
|
46
|
+
|
|
47
|
+
| Priority | Section | Action |
|
|
48
|
+
|----------|---------|--------|
|
|
49
|
+
| 1 | **Cycles** | Break production file dependency cycles (`cache`↔`scope` was one) |
|
|
50
|
+
| 2 | **Unreferenced / dead exports** | No ref usage / no external refs — verify with `rg`, delete or `_` prefix |
|
|
51
|
+
| 3 | **Same-file only** | Module-private by usage — rename to `_` |
|
|
52
|
+
| 4 | **Stale types** | Low-consumer classes — merge or justify |
|
|
53
|
+
|
|
54
|
+
`analyze` skips test paths by default (`tests/`, `*.test.*`, `*.spec.*`); `--include-tests` to include. Reindex after large edits.
|
|
55
|
+
|
|
56
|
+
Do **not** spawn broad code-review agents until this pass is done (or explain why skipped).
|
|
57
|
+
|
|
58
|
+
## Analyze feedback loop (mandatory)
|
|
59
|
+
|
|
60
|
+
When you or a review subagent finds a repo issue — bug, dead code, cycle, risky hub, stale type, unused import — **stop and ask first:**
|
|
61
|
+
|
|
62
|
+
> *Could our SQLite index have predicted this, and `analyze` just doesn't surface it yet?*
|
|
63
|
+
|
|
64
|
+
If **yes** (the signal is in `documents`, `mentions`, `global_symbols`, `defn_enclosing_ranges`):
|
|
65
|
+
|
|
66
|
+
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`.
|
|
67
|
+
2. **Dogfood** — `reindex` → confirm the issue appears (or the false positive is filtered).
|
|
68
|
+
3. **Then** fix the production code (or document a known blind spot).
|
|
69
|
+
|
|
70
|
+
Only skip step 1 when the issue is **outside the index** (runtime, CLI UX, docs drift, git, env, concurrency, test harness).
|
|
71
|
+
|
|
72
|
+
### Retrospective: caught manually, SQLite already had it
|
|
73
|
+
|
|
74
|
+
| Issue we hit | Index signal | Analyze today | Gap / next check |
|
|
75
|
+
|--------------|--------------|---------------|------------------|
|
|
76
|
+
| `cache` ↔ `scope` import cycle | cross-file `mentions` edges | `[high] Cycles` | **Caught** — keep dogfooding cycles |
|
|
77
|
+
| Cross-file dead export (`get_refs_for_symbols`) | def with no external `mentions` | `[high] Dead exports` | **Caught** |
|
|
78
|
+
| Same-file-only dead code | def, `role=0` only in def file | `[high] Unreferenced` or `[medium] Same-file only` | **Caught** (since extended) |
|
|
79
|
+
| Same-file helper without `_` (`run_with_fallback`) | same-file `role=0` or none | `[medium] Same-file only` / unreferenced | **Caught** — rename to `_` |
|
|
80
|
+
| 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` |
|
|
81
|
+
| `analyze/*` section runners “dead” | no external refs | noise filter in `common.py` | **Filtered** — framework pattern |
|
|
82
|
+
| Unused import | `role=2` mention, no in-file use | `[high] Unused imports` (per file) | **Caught** on file target |
|
|
83
|
+
| 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 |
|
|
84
|
+
| 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` |
|
|
85
|
+
| 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 |
|
|
86
|
+
| Duplicate / parallel helpers | — | — | **Not in index** — `rg`, not analyze |
|
|
87
|
+
|
|
88
|
+
Add new rows to `dogfood.md` when you find another gap; implement the SQL check before the next manual review pass.
|
|
89
|
+
|
|
90
|
+
### Size / complexity checks (assessed — don’t promote to high/medium)
|
|
91
|
+
|
|
92
|
+
SQLite has **line ranges** (`defn_enclosing_ranges`) so LOC is cheap. That does **not** mean “big function” belongs next to dead exports.
|
|
93
|
+
|
|
94
|
+
| Idea | In index? | Verdict |
|
|
95
|
+
|------|-----------|---------|
|
|
96
|
+
| **LOC ≥ N** alone | Yes | **LOW at best** — noisy (`main`, argparse, legitimate parsers). Not a nuke candidate. |
|
|
97
|
+
| **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. |
|
|
98
|
+
| **LOC + consumers** on file target | Yes | **Change surface** (medium) already sorts by consumers with line ranges — drill there. |
|
|
99
|
+
| **Symbol pressure** | Yes | **Per-symbol** `analyze Foo` shows `loc × fan_in × fan_out`. |
|
|
100
|
+
| **God class / many members** | Yes | Use `members Class` — not analyze. |
|
|
101
|
+
| **File byte size / cyclomatic complexity** | No | Out of scope for SCIP index. |
|
|
102
|
+
| **Fat file (many symbols)** | Yes | Low value; coupling/hotspots approximate module heat. |
|
|
103
|
+
|
|
104
|
+
**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.
|
|
105
|
+
|
|
106
|
+
## TDD
|
|
107
|
+
|
|
108
|
+
1. **Red** — `tests/test_e2e.py` + `fixture_catalog` constants.
|
|
109
|
+
2. **Green** — `scip_cli/commands/*.py`.
|
|
110
|
+
3. **Refactor** — unit tests for pure helpers only.
|
|
111
|
+
|
|
112
|
+
- **E2e** (`cli` fixture): in-process `main()`, TS project indexed once per session — default for behavior.
|
|
113
|
+
- **Unit**: `:memory:` SQLite, `tests/analyze_db.py`, merge/index prune tests.
|
|
114
|
+
- **No subprocess** for CLI tests; no `reindex` in e2e (mutates `~/.cache/scip-cli`).
|
|
115
|
+
- New symbols: extend `tests/fixtures/sample-project/` + `fixture_catalog.py`.
|
|
116
|
+
|
|
117
|
+
## Codebase map (contributors)
|
|
118
|
+
|
|
119
|
+
| Area | Path | Notes |
|
|
120
|
+
|------|------|-------|
|
|
121
|
+
| Commands | `scip_cli/commands/` | Thin; SQL in `queries.py` / `analyze/` |
|
|
122
|
+
| Index build | `scip_cli/indexing.py` | `index.db.next` → promote; flock; `>10` tsconfigs log progress |
|
|
123
|
+
| Variable prune | postprocess + `merge.py` | Omit const/let/var on **COPY**, not DELETE — no `variable` kind |
|
|
124
|
+
| Session | `scip_cli/session.py` | `setup()`, `resolve_one_symbol` (limit 2 for ambiguity) |
|
|
125
|
+
| Analyze filters | `scip_cli/analyze/common.py` | `is_test_path`, `analyze_noise` (`_` helpers) |
|
|
126
|
+
|
|
127
|
+
`todo.md` = tracked work; `dogfood.md` = future ideas only. Wishlist/backlog in `docs/` per workspace rules.
|
|
128
|
+
|
|
129
|
+
## Docs touch points
|
|
130
|
+
|
|
131
|
+
- User install + analyze guide → `README.md`
|
|
132
|
+
- Agent/user CLI reference → `scip_cli/SKILL.md` (must match `__main__.py` flags)
|
|
133
|
+
- 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
|
scip_cli-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scip-cli
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Fast code intelligence via SCIP indexes
|
|
5
|
+
Project-URL: Homepage, https://github.com/flesler/scip-cli
|
|
6
|
+
Author: Ariel Flesler
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
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'
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# scip-cli
|
|
22
|
+
|
|
23
|
+
[](https://badge.fury.io/py/scip-cli)
|
|
24
|
+
[](https://opensource.org/licenses/MIT)
|
|
25
|
+
|
|
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
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
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
|
|
39
|
+
|
|
40
|
+
## For AI Agents
|
|
41
|
+
|
|
42
|
+
Install as a reusable skill so your agent always knows how to navigate the codebase:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
scip-cli skill ~/.claude/skills/scip-cli/ # Claude Code
|
|
46
|
+
scip-cli skill ~/.cursor/skills/scip-cli/ # Cursor
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or dump the quick reference for one-off use:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
scip-cli skill
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
### 1. Install scip-cli
|
|
58
|
+
|
|
59
|
+
**From PyPI** (end users):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install scip-cli
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Local development** (use a project venv — do not rely on global `pip`):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cd scip-cli
|
|
69
|
+
python -m venv .venv
|
|
70
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
71
|
+
pip install -e ".[dev]"
|
|
72
|
+
scip-cli --version
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`pip install -e .` keeps `scip-cli` on your PATH inside the venv while you edit the repo. Run tests with `pytest` from the same venv.
|
|
76
|
+
|
|
77
|
+
### 2. Install prerequisites (optional)
|
|
78
|
+
|
|
79
|
+
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`:
|
|
80
|
+
|
|
81
|
+
**Option A: Zero extra setup (recommended)**
|
|
82
|
+
|
|
83
|
+
Install `scip-cli` and run it. On first index, scip-cli will:
|
|
84
|
+
|
|
85
|
+
- Download `scip-typescript` / `scip-python` via `npx` when not already on PATH
|
|
86
|
+
- Download the `scip` converter binary from [GitHub releases](https://github.com/scip-code/scip/releases) into `~/.cache/scip-cli/bin/` when not already on PATH
|
|
87
|
+
- Walk the repo for `tsconfig*.json` project roots (TypeScript monorepos), run `scip-typescript` per project (parallel by default), convert each partial index, then merge into one `index.db`
|
|
88
|
+
|
|
89
|
+
No `.scip-cli.json` required for discovery. Subsequent queries read the cached database only.
|
|
90
|
+
|
|
91
|
+
**Option B: Install indexers globally ahead of time**
|
|
92
|
+
|
|
93
|
+
Same indexing steps as Option A; this only avoids `npx` download on the first run:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# TypeScript/JavaScript indexer (also handles plain JS via --infer-tsconfig)
|
|
97
|
+
npm install -g @sourcegraph/scip-typescript
|
|
98
|
+
|
|
99
|
+
# Python indexer
|
|
100
|
+
npm install -g @sourcegraph/scip-python
|
|
101
|
+
|
|
102
|
+
# SCIP CLI for index conversion (GitHub release — not on npm)
|
|
103
|
+
# https://github.com/scip-code/scip/releases (v0.8.1+ recommended)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Verify installation:**
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
scip-cli --help
|
|
110
|
+
scip-typescript --version # Only if you chose Option B
|
|
111
|
+
scip --version # Install from GitHub releases; v0.8.1+ recommended
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Usage
|
|
115
|
+
|
|
116
|
+
All commands are subcommands of `scip-cli`:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
scip-cli <command> [arguments]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Commands
|
|
123
|
+
|
|
124
|
+
- `refs <symbol>` - Find all references to a symbol (`--path` to scope)
|
|
125
|
+
- `code <symbol>` - Find symbol definition with source code (`--path`, `--max-lines`, `--full`, `--offset`, `--snippet`, `--line-numbers`)
|
|
126
|
+
- `search <pattern>` - Search symbols by name pattern (`--path`)
|
|
127
|
+
- `symbols <file>` - List all symbols in a file (`--path`; bare filename OK)
|
|
128
|
+
- `rdeps <file>` - Find files that depend on a file (`--path`)
|
|
129
|
+
- `members <symbol>` - List members of a class/interface (`--path`)
|
|
130
|
+
- `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).
|
|
131
|
+
- `reindex` - Force re-indexing of the current project (`--path` to limit scope; repeatable)
|
|
132
|
+
- `skill [path]` - Install or dump the SKILL.md
|
|
133
|
+
|
|
134
|
+
### Examples
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Find where greet is used
|
|
138
|
+
scip-cli refs greet
|
|
139
|
+
|
|
140
|
+
# Get definition of greet
|
|
141
|
+
scip-cli code greet
|
|
142
|
+
|
|
143
|
+
# Search for symbols matching "Widget"
|
|
144
|
+
scip-cli search Widget
|
|
145
|
+
|
|
146
|
+
# Scope to a subdirectory
|
|
147
|
+
scip-cli code greet --path packages/api
|
|
148
|
+
|
|
149
|
+
# List symbols by bare filename
|
|
150
|
+
scip-cli symbols helper.ts
|
|
151
|
+
|
|
152
|
+
# Find files that import from a module
|
|
153
|
+
scip-cli rdeps src/helper.ts
|
|
154
|
+
|
|
155
|
+
# List members of a class
|
|
156
|
+
scip-cli members Widget
|
|
157
|
+
|
|
158
|
+
# Project health dashboard (or: scip-cli analyze src/foo.ts / scip-cli analyze greet)
|
|
159
|
+
scip-cli analyze
|
|
160
|
+
|
|
161
|
+
# Install skill file
|
|
162
|
+
scip-cli skill ~/.claude/skills/scip-cli/SKILL.md
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Pipelines
|
|
166
|
+
|
|
167
|
+
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.
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# What do importers of this file export?
|
|
171
|
+
scip-cli rdeps src/helper.ts | xargs -I{} scip-cli symbols {}
|
|
172
|
+
|
|
173
|
+
# Which files reference a symbol?
|
|
174
|
+
scip-cli refs greet --paths-only
|
|
175
|
+
|
|
176
|
+
# Classes matching a name → list their members
|
|
177
|
+
scip-cli search Handler --kind class --names-only | xargs -I{} scip-cli members {}
|
|
178
|
+
|
|
179
|
+
# Walk class members to their definitions
|
|
180
|
+
scip-cli members Widget --names-only | xargs -I{} scip-cli code Widget.{}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## How It Works
|
|
184
|
+
|
|
185
|
+
1. On first query, automatically detects project language from `package.json` (TS/JS) or `pyproject.toml`/`setup.py` (Python)
|
|
186
|
+
2. For TypeScript monorepos, walks the repository for `tsconfig*.json` project roots (nested ancestors deduped; root included only when its `include` is broad)
|
|
187
|
+
3. Runs `scip-typescript` per project (in parallel when there are multiple projects; set `SCIP_CLI_INDEX_WORKERS=1` to force serial), or `scip-python` for Python
|
|
188
|
+
4. Converts each SCIP output to SQLite with `scip expt-convert`, then merges partial databases when needed
|
|
189
|
+
5. Caches the result in `~/.cache/scip-cli/projects/<dirname>-<hash>/index.db` (e.g. `my-monorepo-1a3f7a`)
|
|
190
|
+
6. Subsequent queries are SQLite lookups against that cache (not re-indexing)
|
|
191
|
+
|
|
192
|
+
## Configuration
|
|
193
|
+
|
|
194
|
+
Optional `.scip-cli.json` in the project root:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"maxHeapMb": 8192,
|
|
199
|
+
"indexRoots": ["packages/core", "apps/worker"],
|
|
200
|
+
"onlyIndexRoots": false
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- `maxHeapMb` — Node heap for `scip-typescript` / `scip-python` (default **8192 MB** when omitted). Overridden by `SCIP_CLI_MAX_HEAP_MB`. This is the V8 heap cap, not total RAM usage.
|
|
205
|
+
- `indexRoots` — extra TypeScript project directories to include on **first index**, merged with auto-discovered projects.
|
|
206
|
+
- `onlyIndexRoots` — skip auto-discovery and index **only** `indexRoots` (smaller initial index when you only care about part of a monorepo).
|
|
207
|
+
|
|
208
|
+
`SCIP_CLI_INDEX_WORKERS` controls parallel `scip-typescript` runs during first index (default: up to 8). Merge into one database is always serial.
|
|
209
|
+
|
|
210
|
+
Large monorepos (>10 tsconfig projects) log per-project progress to stderr during indexing; smaller repos stay quiet aside from the final `Indexed … (size)` line.
|
|
211
|
+
|
|
212
|
+
Scoped indexing without editing `.scip-cli.json`:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
scip-cli reindex --path packages/server
|
|
216
|
+
scip-cli reindex --path packages/api --path packages/worker
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`--path` limits which discovered tsconfig projects are indexed (prefix match, same idea as query `--path`). The scope is saved as `index-scope.json` next to `index.db` and reused until you run a full `scip-cli reindex` with no `--path`.
|
|
220
|
+
|
|
221
|
+
Run `scip-cli reindex` after changing scope, `.scip-cli.json` index settings, or when you want a fresh index.
|
|
222
|
+
|
|
223
|
+
## Finding easy wins with `analyze`
|
|
224
|
+
|
|
225
|
+
Use `analyze` on the repo itself before broad refactors or agent review — it surfaces cross-file issues from the SCIP index (not Python `vulture`).
|
|
226
|
+
|
|
227
|
+
**Quick pass** (after `scip-cli reindex`):
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
scip-cli analyze --limit 25
|
|
231
|
+
scip-cli analyze --priority high --limit 25 # dead exports & cycles only
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Sections are tagged `[high]`, `[medium]`, `[low]` and listed in that order.
|
|
235
|
+
|
|
236
|
+
| Tier | Project sections | Action |
|
|
237
|
+
| ---- | ---------------- | ------ |
|
|
238
|
+
| **high** | Cycles, unreferenced, dead exports, stale types | Nuke or fix cycles; delete unused; `_` prefix |
|
|
239
|
+
| **medium** | Same-file only, change surface (file target) | Module-private by usage |
|
|
240
|
+
| **low** | Test-only consumers, coupling, bottlenecks, hotspots | Noisy on Python (index omits many same-file calls); verify with `rg` |
|
|
241
|
+
|
|
242
|
+
Use `--priority high` for a quick gate; `--priority high,medium` adds context. File drill-down adds change surface and unused imports.
|
|
243
|
+
|
|
244
|
+
**What to look at first**
|
|
245
|
+
|
|
246
|
+
| Section | Easy pickings |
|
|
247
|
+
| ------- | ------------- |
|
|
248
|
+
| **Cycles** | Import/mention cycles between production files — break the edge or extract shared code |
|
|
249
|
+
| **Unreferenced** | No usage in the index at all — delete |
|
|
250
|
+
| **Dead exports** | No external refs — delete or `_` prefix |
|
|
251
|
+
| **Stale types** | Classes/types with ≤1 external consumer — merge, inline, or document why they stay |
|
|
252
|
+
| **Same-file only** | Used only inside defining file — rename to `_` |
|
|
253
|
+
| **Test-only consumers** | Cross-file refs are all from tests — promote to e2e or accept as internal |
|
|
254
|
+
|
|
255
|
+
**Per-file or package drill-down** on hubs or suspects:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
scip-cli analyze scip_cli/queries.py --limit 20 # file: scoped project + per-file + top symbols
|
|
259
|
+
scip-cli analyze scip_cli --limit 15 # directory: scoped project + each file under it
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
`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.
|
|
263
|
+
|
|
264
|
+
**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.
|
|
265
|
+
|
|
266
|
+
**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.
|
|
267
|
+
|
|
268
|
+
## Performance
|
|
269
|
+
|
|
270
|
+
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:
|
|
271
|
+
|
|
272
|
+
- `refs`: 6.4s → 0.03s (213x faster)
|
|
273
|
+
- `code`: 2.8s → 0.05s (56x faster)
|
|
274
|
+
- `search`: 2.6s → 0.03s (87x faster)
|
|
275
|
+
- `symbols`: 0.3s → 0.02s (15x faster)
|
|
276
|
+
- `rdeps`: 0.2s → 0.02s (10x faster)
|
|
277
|
+
- `members`: 3.1s → 0.03s (103x faster)
|
|
278
|
+
|
|
279
|
+
The speedup comes from using optimized direct SQLite queries and cutting some nice but very slow goodies (like ts-morph).
|
|
280
|
+
|
|
281
|
+
## Architecture
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
scip_cli/
|
|
285
|
+
├── __init__.py
|
|
286
|
+
├── __main__.py # CLI entry point
|
|
287
|
+
├── cli_args.py # Shared argparse helpers
|
|
288
|
+
├── config.py # .scip-cli.json loader
|
|
289
|
+
├── discover.py # TypeScript project discovery
|
|
290
|
+
├── merge.py # SQLite index merging
|
|
291
|
+
├── scip_tool.py # scip binary download
|
|
292
|
+
├── sql.py # SQLite helpers
|
|
293
|
+
├── paths.py # --path scope filtering
|
|
294
|
+
├── project.py # Project root + language detection
|
|
295
|
+
├── cache.py # Index cache paths
|
|
296
|
+
├── scope.py # Persisted reindex scope (index-scope.json)
|
|
297
|
+
├── debug.py # SCIP_CLI_DEBUG stderr helpers
|
|
298
|
+
├── indexing.py # SCIP index build + get_db
|
|
299
|
+
├── symbols.py # Symbol parsing and kinds
|
|
300
|
+
├── queries.py # Symbol/file SQL queries
|
|
301
|
+
├── source.py # Filesystem source reads
|
|
302
|
+
├── output.py # CLI formatting helpers
|
|
303
|
+
├── session.py # setup() and single-match resolution
|
|
304
|
+
├── targets.py # file-path heuristics (tests; analyze uses analyze/targets.py)
|
|
305
|
+
├── analyze/ # SQL dashboard queries (project/file/symbol)
|
|
306
|
+
└── commands/ # Subcommand implementations
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Development
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
pip install -e ".[dev]"
|
|
313
|
+
pytest tests/ -q
|
|
314
|
+
pytest tests/ -m integration -q # indexes tests/fixtures/sample-project (needs scip-typescript)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Debug Logging
|
|
318
|
+
|
|
319
|
+
Set `SCIP_CLI_DEBUG=1` to enable SQL query logging to stderr (statements truncated to 200 chars):
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
SCIP_CLI_DEBUG=1 scip-cli refs MyFunction
|
|
323
|
+
# Shows: SQL: SELECT ... | params: (...)
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
This is useful for testing and debugging SQL queries
|
|
327
|
+
|
|
328
|
+
## License
|
|
329
|
+
|
|
330
|
+
MIT
|