scip-cli 1.0.2__tar.gz → 1.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-1.0.2/scip_cli.egg-info → scip_cli-1.1.0}/PKG-INFO +50 -17
- {scip_cli-1.0.2 → scip_cli-1.1.0}/README.md +48 -15
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli/SKILL.md +23 -14
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli/__init__.py +1 -1
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli/__main__.py +45 -20
- scip_cli-1.1.0/scip_cli/commands/def_cmd.py +47 -0
- scip_cli-1.1.0/scip_cli/commands/members.py +86 -0
- scip_cli-1.1.0/scip_cli/commands/rdeps.py +47 -0
- scip_cli-1.1.0/scip_cli/commands/refs.py +116 -0
- scip_cli-1.1.0/scip_cli/commands/reindex.py +26 -0
- scip_cli-1.1.0/scip_cli/commands/search.py +138 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli/commands/skill.py +1 -1
- scip_cli-1.1.0/scip_cli/commands/symbols.py +40 -0
- scip_cli-1.1.0/scip_cli/lib.py +505 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0/scip_cli.egg-info}/PKG-INFO +50 -17
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli.egg-info/SOURCES.txt +1 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/setup.py +8 -2
- scip_cli-1.1.0/tests/test_pure_functions.py +532 -0
- scip_cli-1.0.2/scip_cli/commands/def_cmd.py +0 -50
- scip_cli-1.0.2/scip_cli/commands/members.py +0 -84
- scip_cli-1.0.2/scip_cli/commands/rdeps.py +0 -52
- scip_cli-1.0.2/scip_cli/commands/refs.py +0 -107
- scip_cli-1.0.2/scip_cli/commands/search.py +0 -120
- scip_cli-1.0.2/scip_cli/commands/symbols.py +0 -42
- scip_cli-1.0.2/scip_cli/lib.py +0 -390
- scip_cli-1.0.2/tests/test_pure_functions.py +0 -121
- {scip_cli-1.0.2 → scip_cli-1.1.0}/LICENSE +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/MANIFEST.in +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/pyproject.toml +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli/commands/__init__.py +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli.egg-info/dependency_links.txt +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli.egg-info/entry_points.txt +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/scip_cli.egg-info/top_level.txt +0 -0
- {scip_cli-1.0.2 → scip_cli-1.1.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: scip-cli
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Fast code intelligence via SCIP indexes
|
|
5
5
|
Home-page: https://github.com/flesler/scip-cli
|
|
6
6
|
Author: Ariel Flesler
|
|
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Topic :: Software Development :: Code Generators
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
15
|
Dynamic: author
|
|
@@ -27,11 +27,11 @@ Dynamic: summary
|
|
|
27
27
|
[](https://badge.fury.io/py/scip-cli)
|
|
28
28
|
[](https://opensource.org/licenses/MIT)
|
|
29
29
|
|
|
30
|
-
Fast code intelligence CLI for TypeScript/JavaScript projects. Query SCIP indexes directly via SQLite for instant results.
|
|
30
|
+
Fast code intelligence CLI for TypeScript/JavaScript and Python projects. Query SCIP indexes directly via SQLite for instant results.
|
|
31
31
|
|
|
32
32
|
## Features
|
|
33
33
|
|
|
34
|
-
- **Fast**: Direct SQLite queries,
|
|
34
|
+
- **Fast**: Direct SQLite queries, eliminating skippable overhead
|
|
35
35
|
- **Simple**: Single binary with subcommands
|
|
36
36
|
- **Auto-indexing**: Automatically indexes projects on first query
|
|
37
37
|
- **Token-efficient**: Clean, minimal output optimized for AI consumption
|
|
@@ -40,10 +40,27 @@ Fast code intelligence CLI for TypeScript/JavaScript projects. Query SCIP indexe
|
|
|
40
40
|
|
|
41
41
|
### 1. Install scip-cli
|
|
42
42
|
|
|
43
|
+
**From PyPI:**
|
|
44
|
+
|
|
43
45
|
```bash
|
|
44
46
|
pip install scip-cli
|
|
45
47
|
```
|
|
46
48
|
|
|
49
|
+
**From source (local development):**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/flesler/scip-cli.git
|
|
53
|
+
cd scip-cli
|
|
54
|
+
pip install .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For editable development (where `pip install -e .` fails due to permissions):
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
export PYTHONPATH=/path/to/scip-cli:$PYTHONPATH
|
|
61
|
+
python -m scip_cli --help
|
|
62
|
+
```
|
|
63
|
+
|
|
47
64
|
### 2. Install prerequisites (optional)
|
|
48
65
|
|
|
49
66
|
scip-cli can automatically download the required indexing tools when needed, or you can install them globally for faster performance:
|
|
@@ -55,10 +72,13 @@ Just use scip-cli - it will automatically download the required tools via `npx`
|
|
|
55
72
|
**Option B: Install globally for better performance**
|
|
56
73
|
|
|
57
74
|
```bash
|
|
58
|
-
#
|
|
75
|
+
# TypeScript/JavaScript indexer (also handles plain JS via --infer-tsconfig)
|
|
59
76
|
npm install -g @sourcegraph/scip-typescript
|
|
60
77
|
|
|
61
|
-
#
|
|
78
|
+
# Python indexer
|
|
79
|
+
npm install -g @sourcegraph/scip-python
|
|
80
|
+
|
|
81
|
+
# SCIP CLI for index conversion
|
|
62
82
|
npm install -g @sourcegraph/scip
|
|
63
83
|
```
|
|
64
84
|
|
|
@@ -70,12 +90,6 @@ scip-typescript --version # Only if you chose Option B
|
|
|
70
90
|
scip --version # Only if you chose Option B
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
## Prerequisites
|
|
74
|
-
|
|
75
|
-
- Python 3.7+
|
|
76
|
-
- `scip-typescript` (for indexing TypeScript/JavaScript)
|
|
77
|
-
- `scip` CLI (for converting indexes)
|
|
78
|
-
|
|
79
93
|
## Usage
|
|
80
94
|
|
|
81
95
|
All commands are subcommands of `scip-cli`:
|
|
@@ -92,6 +106,7 @@ scip-cli <command> [arguments]
|
|
|
92
106
|
- `symbols <file>` - List all symbols in a file
|
|
93
107
|
- `rdeps <file>` - Find files that depend on a file
|
|
94
108
|
- `members <symbol>` - List members of a class/interface
|
|
109
|
+
- `reindex` - Force re-indexing of the current project
|
|
95
110
|
- `skill [path]` - Install or dump the SKILL.md
|
|
96
111
|
|
|
97
112
|
### Examples
|
|
@@ -121,14 +136,16 @@ scip-cli skill ~/.claude/skills/scip/SKILL.md
|
|
|
121
136
|
|
|
122
137
|
## How It Works
|
|
123
138
|
|
|
124
|
-
1. On first query, automatically
|
|
125
|
-
2.
|
|
126
|
-
3.
|
|
127
|
-
4.
|
|
139
|
+
1. On first query, automatically detects project language from `package.json` (TS/JS) or `pyproject.toml`/`setup.py` (Python)
|
|
140
|
+
2. Indexes using `scip-typescript` (adds `--infer-tsconfig` for JS-only projects) or `scip-python`
|
|
141
|
+
3. Converts the SCIP index to SQLite using `scip expt-convert`
|
|
142
|
+
4. Caches the database in `~/.cache/scip-cli/projects/<hash>/index.db`
|
|
143
|
+
5. Subsequent queries are instant SQLite lookups
|
|
128
144
|
|
|
129
145
|
## Performance
|
|
130
146
|
|
|
131
|
-
Compared to bash
|
|
147
|
+
Inspired by [scip-query](https://github.com/PlunderStruck/scip-query), scip-cli is a lightweight Python reimplementation optimized for speed. Compared to the original bash wrapper scripts:
|
|
148
|
+
|
|
132
149
|
- `refs`: 6.4s → 0.03s (213x faster)
|
|
133
150
|
- `def`: 2.8s → 0.05s (56x faster)
|
|
134
151
|
- `search`: 2.6s → 0.03s (87x faster)
|
|
@@ -136,6 +153,8 @@ Compared to bash wrappers:
|
|
|
136
153
|
- `rdeps`: 0.2s → 0.02s (10x faster)
|
|
137
154
|
- `members`: 3.1s → 0.03s (103x faster)
|
|
138
155
|
|
|
156
|
+
The speedup comes from direct SQLite queries instead of shell command chains, eliminating subprocess overhead.
|
|
157
|
+
|
|
139
158
|
## Architecture
|
|
140
159
|
|
|
141
160
|
```
|
|
@@ -150,9 +169,23 @@ scip_cli/
|
|
|
150
169
|
├── symbols.py
|
|
151
170
|
├── rdeps.py
|
|
152
171
|
├── members.py
|
|
172
|
+
├── reindex.py
|
|
153
173
|
└── skill.py
|
|
154
174
|
```
|
|
155
175
|
|
|
176
|
+
## Development
|
|
177
|
+
|
|
178
|
+
### Debug Logging
|
|
179
|
+
|
|
180
|
+
Set `SCIP_CLI_DEBUG=1` to enable SQL query logging to stderr:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
SCIP_CLI_DEBUG=1 scip-cli refs MyFunction
|
|
184
|
+
# Shows: SQL: SELECT ... | params: (...)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This is useful for testing and debugging SQL queries without exposing a `--debug` flag to users.
|
|
188
|
+
|
|
156
189
|
## License
|
|
157
190
|
|
|
158
191
|
MIT
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
[](https://badge.fury.io/py/scip-cli)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
Fast code intelligence CLI for TypeScript/JavaScript projects. Query SCIP indexes directly via SQLite for instant results.
|
|
6
|
+
Fast code intelligence CLI for TypeScript/JavaScript and Python projects. Query SCIP indexes directly via SQLite for instant results.
|
|
7
7
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
|
-
- **Fast**: Direct SQLite queries,
|
|
10
|
+
- **Fast**: Direct SQLite queries, eliminating skippable overhead
|
|
11
11
|
- **Simple**: Single binary with subcommands
|
|
12
12
|
- **Auto-indexing**: Automatically indexes projects on first query
|
|
13
13
|
- **Token-efficient**: Clean, minimal output optimized for AI consumption
|
|
@@ -16,10 +16,27 @@ Fast code intelligence CLI for TypeScript/JavaScript projects. Query SCIP indexe
|
|
|
16
16
|
|
|
17
17
|
### 1. Install scip-cli
|
|
18
18
|
|
|
19
|
+
**From PyPI:**
|
|
20
|
+
|
|
19
21
|
```bash
|
|
20
22
|
pip install scip-cli
|
|
21
23
|
```
|
|
22
24
|
|
|
25
|
+
**From source (local development):**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/flesler/scip-cli.git
|
|
29
|
+
cd scip-cli
|
|
30
|
+
pip install .
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For editable development (where `pip install -e .` fails due to permissions):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export PYTHONPATH=/path/to/scip-cli:$PYTHONPATH
|
|
37
|
+
python -m scip_cli --help
|
|
38
|
+
```
|
|
39
|
+
|
|
23
40
|
### 2. Install prerequisites (optional)
|
|
24
41
|
|
|
25
42
|
scip-cli can automatically download the required indexing tools when needed, or you can install them globally for faster performance:
|
|
@@ -31,10 +48,13 @@ Just use scip-cli - it will automatically download the required tools via `npx`
|
|
|
31
48
|
**Option B: Install globally for better performance**
|
|
32
49
|
|
|
33
50
|
```bash
|
|
34
|
-
#
|
|
51
|
+
# TypeScript/JavaScript indexer (also handles plain JS via --infer-tsconfig)
|
|
35
52
|
npm install -g @sourcegraph/scip-typescript
|
|
36
53
|
|
|
37
|
-
#
|
|
54
|
+
# Python indexer
|
|
55
|
+
npm install -g @sourcegraph/scip-python
|
|
56
|
+
|
|
57
|
+
# SCIP CLI for index conversion
|
|
38
58
|
npm install -g @sourcegraph/scip
|
|
39
59
|
```
|
|
40
60
|
|
|
@@ -46,12 +66,6 @@ scip-typescript --version # Only if you chose Option B
|
|
|
46
66
|
scip --version # Only if you chose Option B
|
|
47
67
|
```
|
|
48
68
|
|
|
49
|
-
## Prerequisites
|
|
50
|
-
|
|
51
|
-
- Python 3.7+
|
|
52
|
-
- `scip-typescript` (for indexing TypeScript/JavaScript)
|
|
53
|
-
- `scip` CLI (for converting indexes)
|
|
54
|
-
|
|
55
69
|
## Usage
|
|
56
70
|
|
|
57
71
|
All commands are subcommands of `scip-cli`:
|
|
@@ -68,6 +82,7 @@ scip-cli <command> [arguments]
|
|
|
68
82
|
- `symbols <file>` - List all symbols in a file
|
|
69
83
|
- `rdeps <file>` - Find files that depend on a file
|
|
70
84
|
- `members <symbol>` - List members of a class/interface
|
|
85
|
+
- `reindex` - Force re-indexing of the current project
|
|
71
86
|
- `skill [path]` - Install or dump the SKILL.md
|
|
72
87
|
|
|
73
88
|
### Examples
|
|
@@ -97,14 +112,16 @@ scip-cli skill ~/.claude/skills/scip/SKILL.md
|
|
|
97
112
|
|
|
98
113
|
## How It Works
|
|
99
114
|
|
|
100
|
-
1. On first query, automatically
|
|
101
|
-
2.
|
|
102
|
-
3.
|
|
103
|
-
4.
|
|
115
|
+
1. On first query, automatically detects project language from `package.json` (TS/JS) or `pyproject.toml`/`setup.py` (Python)
|
|
116
|
+
2. Indexes using `scip-typescript` (adds `--infer-tsconfig` for JS-only projects) or `scip-python`
|
|
117
|
+
3. Converts the SCIP index to SQLite using `scip expt-convert`
|
|
118
|
+
4. Caches the database in `~/.cache/scip-cli/projects/<hash>/index.db`
|
|
119
|
+
5. Subsequent queries are instant SQLite lookups
|
|
104
120
|
|
|
105
121
|
## Performance
|
|
106
122
|
|
|
107
|
-
Compared to bash
|
|
123
|
+
Inspired by [scip-query](https://github.com/PlunderStruck/scip-query), scip-cli is a lightweight Python reimplementation optimized for speed. Compared to the original bash wrapper scripts:
|
|
124
|
+
|
|
108
125
|
- `refs`: 6.4s → 0.03s (213x faster)
|
|
109
126
|
- `def`: 2.8s → 0.05s (56x faster)
|
|
110
127
|
- `search`: 2.6s → 0.03s (87x faster)
|
|
@@ -112,6 +129,8 @@ Compared to bash wrappers:
|
|
|
112
129
|
- `rdeps`: 0.2s → 0.02s (10x faster)
|
|
113
130
|
- `members`: 3.1s → 0.03s (103x faster)
|
|
114
131
|
|
|
132
|
+
The speedup comes from direct SQLite queries instead of shell command chains, eliminating subprocess overhead.
|
|
133
|
+
|
|
115
134
|
## Architecture
|
|
116
135
|
|
|
117
136
|
```
|
|
@@ -126,9 +145,23 @@ scip_cli/
|
|
|
126
145
|
├── symbols.py
|
|
127
146
|
├── rdeps.py
|
|
128
147
|
├── members.py
|
|
148
|
+
├── reindex.py
|
|
129
149
|
└── skill.py
|
|
130
150
|
```
|
|
131
151
|
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
### Debug Logging
|
|
155
|
+
|
|
156
|
+
Set `SCIP_CLI_DEBUG=1` to enable SQL query logging to stderr:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
SCIP_CLI_DEBUG=1 scip-cli refs MyFunction
|
|
160
|
+
# Shows: SQL: SELECT ... | params: (...)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This is useful for testing and debugging SQL queries without exposing a `--debug` flag to users.
|
|
164
|
+
|
|
132
165
|
## License
|
|
133
166
|
|
|
134
167
|
MIT
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: scip-cli
|
|
3
|
-
description: Read when needing to find symbols, definitions, references, or members in TypeScript/JavaScript code
|
|
3
|
+
description: Read when needing to find symbols, definitions, references, or members in TypeScript/JavaScript or Python code
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
TypeScript/JavaScript
|
|
6
|
+
TypeScript/JavaScript (.ts, .tsx, .js, .jsx) and Python (.py) — not GraphQL, CSS, or other files.
|
|
7
7
|
|
|
8
8
|
All commands are sub-commands of `scip-cli`. Run from the project root.
|
|
9
9
|
|
|
@@ -11,8 +11,8 @@ All commands are sub-commands of `scip-cli`. Run from the project root.
|
|
|
11
11
|
|
|
12
12
|
| Question | Use | What you get |
|
|
13
13
|
|----------|-----|--------------|
|
|
14
|
-
| "Where is X defined and what does it do?" | `def X` | Functions: full body. Classes: full definition.
|
|
15
|
-
| "Where is X used/called?" | `refs X` | All file:line locations
|
|
14
|
+
| "Where is X defined and what does it do?" | `def X` | Functions: full body. Classes: full definition. Use `--limit` to cap results |
|
|
15
|
+
| "Where is X used/called?" | `refs X` | All file:line locations. Shows refs for all matching symbols. Use `--limit` to cap |
|
|
16
16
|
| "What's in this file?" | `symbols file` | All symbols — bare filename works (`HistoryTab`, `usePatientEntries`) |
|
|
17
17
|
| "Find symbols by name" | `search name` | Functions, types, interfaces, classes. Use `--kind variable` for consts |
|
|
18
18
|
| "What files depend on this file?" | `rdeps file` | Importers — bare name works |
|
|
@@ -20,53 +20,62 @@ All commands are sub-commands of `scip-cli`. Run from the project root.
|
|
|
20
20
|
|
|
21
21
|
## Gotchas
|
|
22
22
|
|
|
23
|
-
- **Bare names** resolve functions, types (aliases + interfaces), and classes. Consts/variables need `def --
|
|
24
|
-
- **Ambiguous types** (e.g. `Opts` in multiple hooks) — `def` returns all; `refs`
|
|
25
|
-
- **First run** in a project may auto-index (one-time wait, ~10-30s for large codebases).
|
|
26
|
-
- **Precision escape hatch**: qualified names like `src:hooks:usePatientEntries:usePatientEntries()` always work.
|
|
23
|
+
- **Bare names** resolve functions, types (aliases + interfaces), and classes. Consts/variables need `def --kind variable X` or `search --kind variable X`. Class methods need `members ClassName`, not bare `def methodName`.
|
|
24
|
+
- **Ambiguous types** (e.g. `Opts` in multiple hooks) — `def` returns all matches; `refs` returns refs for all matching symbols. Use `--limit N` to cap results, or use `search` with a more specific pattern to disambiguate.
|
|
25
|
+
- **First run** in a project may auto-index (one-time wait, ~10-30s for large codebases). JS-only projects (no `tsconfig.json`) are supported automatically.
|
|
27
26
|
|
|
28
27
|
## Details
|
|
29
28
|
|
|
30
29
|
### def
|
|
31
30
|
|
|
32
31
|
```bash
|
|
33
|
-
def [--
|
|
32
|
+
def [--kind <kind>] [--limit N] <symbol>
|
|
34
33
|
```
|
|
35
34
|
|
|
36
|
-
Kinds: `function`, `
|
|
35
|
+
Kinds: `function`, `method`, `class`, `property`, `variable` — use `--kind` when the bare name isn't in the default set above.
|
|
36
|
+
|
|
37
|
+
Default `--limit` is 10. Use `--limit 0` for unlimited (not recommended for large codebases).
|
|
37
38
|
|
|
38
39
|
### refs
|
|
39
40
|
|
|
40
41
|
```bash
|
|
41
|
-
refs <symbol>
|
|
42
|
+
refs [--limit N] <symbol>
|
|
42
43
|
```
|
|
43
44
|
|
|
44
45
|
Returns `file:line` for each reference. Reads source files to find exact line numbers.
|
|
45
46
|
|
|
47
|
+
Default `--limit` is 10. When multiple symbols match, refs are grouped by symbol with `# <symbol>` headers.
|
|
48
|
+
|
|
46
49
|
### search
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
|
-
search [--kind <kind>] <pattern>
|
|
52
|
+
search [--kind <kind>] [--limit N] <pattern>
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
Returns `file:line Kind symbolName`. Filters noisy symbols (file-level, parameters, type literals).
|
|
53
56
|
|
|
57
|
+
Default `--limit` is 10.
|
|
58
|
+
|
|
54
59
|
### symbols
|
|
55
60
|
|
|
56
61
|
```bash
|
|
57
|
-
symbols <file>
|
|
62
|
+
symbols [--limit N] <file>
|
|
58
63
|
```
|
|
59
64
|
|
|
60
65
|
Returns `startLine-endLine kind name` for each symbol in the file.
|
|
61
66
|
|
|
67
|
+
Default `--limit` is 10.
|
|
68
|
+
|
|
62
69
|
### rdeps
|
|
63
70
|
|
|
64
71
|
```bash
|
|
65
|
-
rdeps <file>
|
|
72
|
+
rdeps [--limit N] <file>
|
|
66
73
|
```
|
|
67
74
|
|
|
68
75
|
Returns list of files that import from this file.
|
|
69
76
|
|
|
77
|
+
Default `--limit` is 10.
|
|
78
|
+
|
|
70
79
|
### members
|
|
71
80
|
|
|
72
81
|
```bash
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""scip-cli: Fast code intelligence via SCIP indexes."""
|
|
2
|
-
__version__ = "1.0
|
|
2
|
+
__version__ = "1.1.0"
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
"""CLI entry point for scip-cli."""
|
|
3
2
|
import argparse
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
5
6
|
|
|
6
7
|
from . import __version__
|
|
7
|
-
from .
|
|
8
|
+
from .lib import SymbolKind
|
|
9
|
+
from .commands import refs, def_cmd, search, symbols, rdeps, members, skill, reindex
|
|
10
|
+
|
|
11
|
+
# Set up debug logging based on SCIP_CLI_DEBUG env var
|
|
12
|
+
if os.environ.get("SCIP_CLI_DEBUG"):
|
|
13
|
+
logging.basicConfig(
|
|
14
|
+
level=logging.DEBUG,
|
|
15
|
+
format="%(name)s: %(message)s",
|
|
16
|
+
stream=sys.stderr
|
|
17
|
+
)
|
|
18
|
+
else:
|
|
19
|
+
logging.disable(logging.DEBUG)
|
|
8
20
|
|
|
9
21
|
|
|
10
22
|
def main():
|
|
@@ -18,23 +30,28 @@ def main():
|
|
|
18
30
|
# refs
|
|
19
31
|
refs_parser = subparsers.add_parser("refs", help="Find references to a symbol")
|
|
20
32
|
refs_parser.add_argument("symbol", help="Symbol name")
|
|
33
|
+
refs_parser.add_argument("--limit", type=int, default=10, help="Max results (default: 10)")
|
|
21
34
|
|
|
22
35
|
# def
|
|
23
36
|
def_parser = subparsers.add_parser("def", help="Find symbol definition")
|
|
24
|
-
def_parser.add_argument("--
|
|
37
|
+
def_parser.add_argument("--kind", choices=SymbolKind.filterable_values(), help="Filter by kind")
|
|
38
|
+
def_parser.add_argument("--limit", type=int, default=10, help="Max results (default: 10)")
|
|
25
39
|
def_parser.add_argument("symbol", help="Symbol name")
|
|
26
40
|
|
|
27
41
|
# search
|
|
28
42
|
search_parser = subparsers.add_parser("search", help="Search symbols by pattern")
|
|
29
|
-
search_parser.add_argument("--kind", help="Filter by kind")
|
|
43
|
+
search_parser.add_argument("--kind", choices=SymbolKind.filterable_values(), help="Filter by kind")
|
|
44
|
+
search_parser.add_argument("--limit", type=int, default=10, help="Max results (default: 10)")
|
|
30
45
|
search_parser.add_argument("pattern", help="Search pattern")
|
|
31
46
|
|
|
32
47
|
# symbols
|
|
33
48
|
symbols_parser = subparsers.add_parser("symbols", help="List symbols in a file")
|
|
49
|
+
symbols_parser.add_argument("--limit", type=int, default=10, help="Max results (default: 10)")
|
|
34
50
|
symbols_parser.add_argument("file", help="File path or pattern")
|
|
35
51
|
|
|
36
52
|
# rdeps
|
|
37
53
|
rdeps_parser = subparsers.add_parser("rdeps", help="Find reverse dependencies of a file")
|
|
54
|
+
rdeps_parser.add_argument("--limit", type=int, default=10, help="Max results (default: 10)")
|
|
38
55
|
rdeps_parser.add_argument("file", help="File path or pattern")
|
|
39
56
|
|
|
40
57
|
# members
|
|
@@ -45,27 +62,35 @@ def main():
|
|
|
45
62
|
skill_parser = subparsers.add_parser("skill", help="Install or dump the scip-cli SKILL.md")
|
|
46
63
|
skill_parser.add_argument("path", nargs="?", help="Optional file path to write to (creates dirs)")
|
|
47
64
|
|
|
65
|
+
# reindex
|
|
66
|
+
subparsers.add_parser("reindex", help="Force re-indexing of the current project")
|
|
67
|
+
|
|
48
68
|
args = parser.parse_args()
|
|
49
69
|
|
|
50
|
-
|
|
70
|
+
# Dispatch to command handlers
|
|
71
|
+
dispatch = {
|
|
72
|
+
"refs": refs.main,
|
|
73
|
+
"def": def_cmd.main,
|
|
74
|
+
"search": search.main,
|
|
75
|
+
"symbols": symbols.main,
|
|
76
|
+
"rdeps": rdeps.main,
|
|
77
|
+
"members": members.main,
|
|
78
|
+
"skill": skill.main,
|
|
79
|
+
"reindex": reindex.main,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
handler = dispatch.get(args.command)
|
|
83
|
+
if not handler:
|
|
51
84
|
parser.print_help()
|
|
52
85
|
sys.exit(1)
|
|
53
86
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
elif args.command == "symbols":
|
|
62
|
-
symbols.main(args)
|
|
63
|
-
elif args.command == "rdeps":
|
|
64
|
-
rdeps.main(args)
|
|
65
|
-
elif args.command == "members":
|
|
66
|
-
members.main(args)
|
|
67
|
-
elif args.command == "skill":
|
|
68
|
-
skill.main(args)
|
|
87
|
+
try:
|
|
88
|
+
handler(args)
|
|
89
|
+
except RuntimeError as e:
|
|
90
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
except KeyboardInterrupt:
|
|
93
|
+
sys.exit(130)
|
|
69
94
|
|
|
70
95
|
|
|
71
96
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""def command - find symbol definitions."""
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from ..lib import (
|
|
5
|
+
setup,
|
|
6
|
+
resolve_symbol,
|
|
7
|
+
read_source_lines,
|
|
8
|
+
infer_kind,
|
|
9
|
+
get_def_location,
|
|
10
|
+
format_line_range,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main(args):
|
|
15
|
+
"""Find the definition of a symbol."""
|
|
16
|
+
db, project_root = setup()
|
|
17
|
+
try:
|
|
18
|
+
limit = args.limit
|
|
19
|
+
symbols = resolve_symbol(db, args.symbol, args.kind, limit=limit + 1)
|
|
20
|
+
if not symbols:
|
|
21
|
+
print(f"Symbol '{args.symbol}' not found", file=sys.stderr)
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
hit_limit = len(symbols) > limit
|
|
25
|
+
symbols = symbols[:limit]
|
|
26
|
+
|
|
27
|
+
for symbol_id, symbol_str, display_name in symbols:
|
|
28
|
+
row = get_def_location(db, symbol_id)
|
|
29
|
+
if not row:
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
rel_path, start_line, end_line = row
|
|
33
|
+
kind = infer_kind(symbol_str)
|
|
34
|
+
|
|
35
|
+
lines = read_source_lines(project_root, rel_path, start_line, end_line)
|
|
36
|
+
if lines is None:
|
|
37
|
+
source_snippet = "(could not read source)"
|
|
38
|
+
else:
|
|
39
|
+
source_snippet = ''.join(lines).rstrip('\n')
|
|
40
|
+
|
|
41
|
+
print(f"{rel_path}:{format_line_range(start_line, end_line)}")
|
|
42
|
+
print(source_snippet)
|
|
43
|
+
|
|
44
|
+
if hit_limit:
|
|
45
|
+
print(f"# Warning: more than {limit} symbols match, showing first {limit}", file=sys.stderr)
|
|
46
|
+
finally:
|
|
47
|
+
db.close()
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""members command - list members of a class/interface."""
|
|
2
|
+
import sys
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from ..lib import (
|
|
6
|
+
setup,
|
|
7
|
+
resolve_one_symbol,
|
|
8
|
+
get_members,
|
|
9
|
+
get_def_location,
|
|
10
|
+
infer_kind,
|
|
11
|
+
extract_leaf_name,
|
|
12
|
+
read_source_lines,
|
|
13
|
+
format_line_range,
|
|
14
|
+
SymbolKind,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _member_source_patterns(member_symbol, short, kind):
|
|
19
|
+
"""Build TS/JS and Python regex patterns for finding a member's source line."""
|
|
20
|
+
if "<constructor>" in member_symbol:
|
|
21
|
+
ts_pattern = r'^\s*constructor\s*\('
|
|
22
|
+
elif "<get>" in member_symbol:
|
|
23
|
+
ts_pattern = rf'^\s*(?:public\s+|private\s+|protected\s+|static\s+|readonly\s+)*get\s+{re.escape(short)}\s*\('
|
|
24
|
+
elif "<set>" in member_symbol:
|
|
25
|
+
ts_pattern = rf'^\s*(?:public\s+|private\s+|protected\s+|static\s+|readonly\s+)*set\s+{re.escape(short)}\s*\('
|
|
26
|
+
else:
|
|
27
|
+
ts_pattern = rf'^\s*(?:public\s+|private\s+|protected\s+|static\s+|readonly\s+)*{re.escape(short)}\s*\??\s*[:=(]'
|
|
28
|
+
|
|
29
|
+
py_pattern = None
|
|
30
|
+
if kind == SymbolKind.METHOD:
|
|
31
|
+
py_pattern = rf'^\s*(?:async\s+)?def\s+{re.escape(short)}\s*\('
|
|
32
|
+
elif kind == SymbolKind.PROPERTY:
|
|
33
|
+
py_pattern = rf'^\s*{re.escape(short)}\s*[=:]'
|
|
34
|
+
elif kind == SymbolKind.CLASS:
|
|
35
|
+
py_pattern = rf'^\s*class\s+{re.escape(short)}\s*[:\(]'
|
|
36
|
+
|
|
37
|
+
return ts_pattern, py_pattern
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def main(args):
|
|
41
|
+
"""List members of a class or interface."""
|
|
42
|
+
db, project_root = setup()
|
|
43
|
+
try:
|
|
44
|
+
symbol_id, _, _ = resolve_one_symbol(db, args.symbol)
|
|
45
|
+
members = get_members(db, symbol_id)
|
|
46
|
+
|
|
47
|
+
if not members:
|
|
48
|
+
print(f"No members found for '{args.symbol}'", file=sys.stderr)
|
|
49
|
+
sys.exit(1)
|
|
50
|
+
|
|
51
|
+
parent_def = get_def_location(db, symbol_id)
|
|
52
|
+
parent_file = parent_def[0] if parent_def else None
|
|
53
|
+
parent_start = parent_def[1] if parent_def else None
|
|
54
|
+
parent_end = parent_def[2] if parent_def else None
|
|
55
|
+
|
|
56
|
+
needs_lookup = any(m[3] is None for m in members)
|
|
57
|
+
source_lines = None
|
|
58
|
+
if needs_lookup and project_root and parent_file and parent_start is not None:
|
|
59
|
+
source_lines = read_source_lines(project_root, parent_file, parent_start, parent_end)
|
|
60
|
+
|
|
61
|
+
for member_id, member_symbol, member_name, start_line, end_line in members:
|
|
62
|
+
kind = infer_kind(member_symbol)
|
|
63
|
+
short = extract_leaf_name(member_symbol)
|
|
64
|
+
|
|
65
|
+
if start_line is None and source_lines:
|
|
66
|
+
ts_pattern, py_pattern = _member_source_patterns(member_symbol, short, kind)
|
|
67
|
+
patterns = []
|
|
68
|
+
if parent_file and parent_file.endswith('.py'):
|
|
69
|
+
if py_pattern:
|
|
70
|
+
patterns.append(py_pattern)
|
|
71
|
+
patterns.append(ts_pattern)
|
|
72
|
+
else:
|
|
73
|
+
patterns.append(ts_pattern)
|
|
74
|
+
if py_pattern:
|
|
75
|
+
patterns.append(py_pattern)
|
|
76
|
+
|
|
77
|
+
for i, line in enumerate(source_lines):
|
|
78
|
+
if any(re.match(p, line) for p in patterns):
|
|
79
|
+
start_line = parent_start + i
|
|
80
|
+
end_line = start_line
|
|
81
|
+
break
|
|
82
|
+
|
|
83
|
+
line_info = format_line_range(start_line, end_line)
|
|
84
|
+
print(f"{line_info} {kind} {short}")
|
|
85
|
+
finally:
|
|
86
|
+
db.close()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""rdeps command - find reverse dependencies of a file."""
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from ..lib import (
|
|
5
|
+
setup,
|
|
6
|
+
resolve_one_file,
|
|
7
|
+
get_file_symbols,
|
|
8
|
+
get_refs_for_symbols,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main(args):
|
|
13
|
+
"""Find all files that import from this file."""
|
|
14
|
+
db, _ = setup()
|
|
15
|
+
try:
|
|
16
|
+
limit = args.limit
|
|
17
|
+
file_path = resolve_one_file(db, args.file)
|
|
18
|
+
|
|
19
|
+
symbols = get_file_symbols(db, file_path)
|
|
20
|
+
if not symbols:
|
|
21
|
+
print(f"No symbols found in '{file_path}'", file=sys.stderr)
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
symbol_ids = [s[0] for s in symbols]
|
|
25
|
+
refs = get_refs_for_symbols(db, symbol_ids)
|
|
26
|
+
|
|
27
|
+
rdeps = set()
|
|
28
|
+
for symbol_id, ref_list in refs.items():
|
|
29
|
+
for ref_path, ref_line in ref_list:
|
|
30
|
+
if ref_path != file_path:
|
|
31
|
+
rdeps.add(ref_path)
|
|
32
|
+
|
|
33
|
+
if not rdeps:
|
|
34
|
+
print(f"No reverse dependencies found for '{file_path}'", file=sys.stderr)
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
sorted_rdeps = sorted(rdeps)
|
|
38
|
+
hit_limit = len(sorted_rdeps) > limit
|
|
39
|
+
sorted_rdeps = sorted_rdeps[:limit]
|
|
40
|
+
|
|
41
|
+
for dep_path in sorted_rdeps:
|
|
42
|
+
print(dep_path)
|
|
43
|
+
|
|
44
|
+
if hit_limit:
|
|
45
|
+
print(f"# Warning: more than {limit} reverse dependencies, showing first {limit}", file=sys.stderr)
|
|
46
|
+
finally:
|
|
47
|
+
db.close()
|