uncoded 0.7.0__tar.gz → 1.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.
- {uncoded-0.7.0 → uncoded-1.0.0}/.agents/skills/coherence-review/SKILL.md +21 -22
- {uncoded-0.7.0 → uncoded-1.0.0}/.claude/skills/coherence-review/SKILL.md +21 -22
- {uncoded-0.7.0 → uncoded-1.0.0}/.github/workflows/ci.yml +1 -1
- {uncoded-0.7.0 → uncoded-1.0.0}/.gitignore +0 -5
- {uncoded-0.7.0 → uncoded-1.0.0}/.pre-commit-config.yaml +0 -5
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/namespace.yaml +165 -53
- uncoded-1.0.0/.uncoded/stubs/src/uncoded/ast_helpers.pyi +9 -0
- uncoded-1.0.0/.uncoded/stubs/src/uncoded/body.pyi +11 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/cli.pyi +12 -1
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/config.pyi +0 -3
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/extract.pyi +1 -6
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/instruction_files.pyi +2 -1
- uncoded-1.0.0/.uncoded/stubs/src/uncoded/refs.pyi +54 -0
- uncoded-1.0.0/.uncoded/stubs/src/uncoded/resolver.pyi +34 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/stubs.pyi +2 -2
- uncoded-1.0.0/.uncoded/stubs/tests/test_body.pyi +145 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_cli.pyi +72 -3
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_config.pyi +1 -14
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_extract.pyi +11 -2
- uncoded-1.0.0/.uncoded/stubs/tests/test_refs.pyi +88 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_stubs.pyi +23 -14
- {uncoded-0.7.0 → uncoded-1.0.0}/AGENTS.md +58 -64
- {uncoded-0.7.0 → uncoded-1.0.0}/PKG-INFO +68 -75
- {uncoded-0.7.0 → uncoded-1.0.0}/README.md +65 -73
- {uncoded-0.7.0 → uncoded-1.0.0}/pyproject.toml +12 -1
- uncoded-1.0.0/src/uncoded/ast_helpers.py +30 -0
- uncoded-1.0.0/src/uncoded/body.py +32 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/cli.py +122 -22
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/config.py +0 -23
- uncoded-1.0.0/src/uncoded/dispatch_rule.md +104 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/extract.py +5 -30
- uncoded-1.0.0/src/uncoded/instruction_files.py +64 -0
- uncoded-1.0.0/src/uncoded/refs.py +231 -0
- uncoded-1.0.0/src/uncoded/resolver.py +163 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/skill.py +21 -22
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/stubs.py +8 -9
- uncoded-1.0.0/tests/test_body.py +470 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_cli.py +256 -6
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_config.py +0 -18
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_extract.py +33 -2
- uncoded-1.0.0/tests/test_refs.py +319 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_stubs.py +289 -110
- uncoded-1.0.0/uv.lock +329 -0
- uncoded-0.7.0/.claude/settings.json +0 -18
- uncoded-0.7.0/.mcp.json +0 -20
- uncoded-0.7.0/.serena/project.yml +0 -166
- uncoded-0.7.0/.uncoded/reviews/2026-04-25-001215.md +0 -150
- uncoded-0.7.0/.uncoded/stubs/src/uncoded/serena_setup.pyi +0 -26
- uncoded-0.7.0/.uncoded/stubs/tests/test_serena_setup.pyi +0 -63
- uncoded-0.7.0/resources/lsp-research.md +0 -45
- uncoded-0.7.0/src/uncoded/instruction_files.py +0 -176
- uncoded-0.7.0/src/uncoded/serena_setup.py +0 -216
- uncoded-0.7.0/tests/test_serena_setup.py +0 -228
- uncoded-0.7.0/uv.lock +0 -229
- {uncoded-0.7.0 → uncoded-1.0.0}/.github/workflows/publish.yml +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/__init__.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/namespace_map.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/skill.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/src/uncoded/sync.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_instruction_files.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_namespace_map.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_skill.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_sync.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/.uncoded/stubs/tests/test_uncoded.pyi +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/CLAUDE.md +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/LICENSE +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/__init__.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/namespace_map.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/src/uncoded/sync.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/__init__.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_instruction_files.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_namespace_map.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_skill.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_sync.py +0 -0
- {uncoded-0.7.0 → uncoded-1.0.0}/tests/test_uncoded.py +0 -0
|
@@ -45,9 +45,8 @@ Verify by reading `.uncoded/namespace.yaml` — if it exists and is non-empty,
|
|
|
45
45
|
proceed. If not, stop and tell the user to run `uncoded sync` first; the review
|
|
46
46
|
depends on the index.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
cross-file reference checks.
|
|
48
|
+
The structural sweep uses `uncoded refs` for cross-file reference checks —
|
|
49
|
+
it ships with uncoded itself and is always available when the index is present.
|
|
51
50
|
|
|
52
51
|
## Workflow
|
|
53
52
|
|
|
@@ -57,7 +56,7 @@ The review proceeds in four sweeps, each building on the previous:
|
|
|
57
56
|
2. **Lexical sweep** — read the namespace, look for naming-level inconsistency.
|
|
58
57
|
3. **Promissory sweep** — check each symbol's name / signature / docstring
|
|
59
58
|
for internal disagreement; names and signatures from the stub, docstrings
|
|
60
|
-
via `
|
|
59
|
+
via `uncoded body`.
|
|
61
60
|
4. **Structural sweep** — combine namespace and imports to find boundary and
|
|
62
61
|
shape symptoms.
|
|
63
62
|
|
|
@@ -97,8 +96,7 @@ model the same entity.
|
|
|
97
96
|
|
|
98
97
|
Detection: scan the namespace for symbol clusters with verb or noun overlap.
|
|
99
98
|
Where suspicion arises, check the stub signatures and the source docstrings
|
|
100
|
-
(via
|
|
101
|
-
candidates overlap in meaning.
|
|
99
|
+
(via `uncoded body`) to confirm the candidates overlap in meaning.
|
|
102
100
|
|
|
103
101
|
**Qualifier accretion.** Names carrying modifiers that are fossils of
|
|
104
102
|
iteration: `_new`, `_v2`, `_updated`, `_legacy`, `_real`, `_proper`, `_final`,
|
|
@@ -121,17 +119,18 @@ subtly different meanings — visible as different signatures, different docstri
|
|
|
121
119
|
content, or different domain associations.
|
|
122
120
|
|
|
123
121
|
Detection: identify name collisions in the namespace, then compare signatures
|
|
124
|
-
(from the stubs) and docstrings (via
|
|
125
|
-
|
|
122
|
+
(from the stubs) and docstrings (via `uncoded body`) to see whether the uses
|
|
123
|
+
agree.
|
|
126
124
|
|
|
127
125
|
## Step 3: Promissory sweep
|
|
128
126
|
|
|
129
127
|
Examine each public symbol's name / signature / docstring triple for internal
|
|
130
128
|
disagreement. Load each source file's stub once for the names and signatures
|
|
131
129
|
across that file's symbols. Then, for each non-trivial public symbol (skip
|
|
132
|
-
trivial one-liners and `__init__` with no meaningful body),
|
|
133
|
-
`
|
|
134
|
-
|
|
130
|
+
trivial one-liners and `__init__` with no meaningful body), run
|
|
131
|
+
`uncoded body <name_path> --in <relative_path>` to read the symbol's source.
|
|
132
|
+
The docstring is at the top; the rest of the body is available for any
|
|
133
|
+
finding that needs it.
|
|
135
134
|
|
|
136
135
|
**Name–signature mismatch.** Does the name's verb fit the signature's return? A
|
|
137
136
|
function called `validate_*` that returns the validated object rather than
|
|
@@ -153,19 +152,20 @@ this for Y; use Z instead." These are confessions — someone noticed drift and
|
|
|
153
152
|
documented it rather than fixing it.
|
|
154
153
|
|
|
155
154
|
Quote evidence verbatim. The stub excerpt is the evidence for name and
|
|
156
|
-
signature findings; the docstring
|
|
157
|
-
|
|
155
|
+
signature findings; the docstring read via `uncoded body` is the evidence
|
|
156
|
+
for any docstring-related finding.
|
|
158
157
|
|
|
159
|
-
**When
|
|
160
|
-
|
|
158
|
+
**When confidence needs the body.** Consult the implementation in the body,
|
|
159
|
+
not just the docstring, when a finding's confidence needs it: a
|
|
160
|
+
name–behaviour mismatch the docstring alone doesn't settle, or a defensive
|
|
161
161
|
docstring you want to verify against the body. Targeted to the symbol, no
|
|
162
162
|
offset arithmetic, no risk of over-reading. Never read a whole source file
|
|
163
163
|
during this sweep.
|
|
164
164
|
|
|
165
165
|
## Step 4: Structural sweep
|
|
166
166
|
|
|
167
|
-
Combine the namespace with the import graph and
|
|
168
|
-
reference resolution.
|
|
167
|
+
Combine the namespace with the import graph and `uncoded refs` for
|
|
168
|
+
cross-file reference resolution.
|
|
169
169
|
|
|
170
170
|
**Overgrown public surfaces / god modules.** A module or class whose public
|
|
171
171
|
namespace is much larger than its siblings, or spans obviously different
|
|
@@ -191,8 +191,8 @@ Check systematically, not by spot-check:
|
|
|
191
191
|
2. Cross-reference with stub import sections — any symbol imported by another
|
|
192
192
|
source module is live; remove it from the candidate list. This culls the
|
|
193
193
|
obvious cases cheaply.
|
|
194
|
-
3. For remaining candidates, use
|
|
195
|
-
|
|
194
|
+
3. For remaining candidates, use `uncoded refs <name_path> --in <relative_path>`
|
|
195
|
+
to verify. Empty output confirms zero callers.
|
|
196
196
|
4. Distinguish two sub-cases when reporting:
|
|
197
197
|
- *No callers anywhere* — dead code; highest priority.
|
|
198
198
|
- *Callers only in tests* — the symbol is tested but not used in source;
|
|
@@ -203,8 +203,7 @@ function in the same module where the function's sole body is `return
|
|
|
203
203
|
<constant>`. Both symbols being public exposes an implementation detail
|
|
204
204
|
unnecessarily — only one needs to be public. Detection: use the stubs to find
|
|
205
205
|
public parameterless functions near public constants, then verify each
|
|
206
|
-
candidate body with
|
|
207
|
-
reporting.
|
|
206
|
+
candidate body with `uncoded body` before reporting.
|
|
208
207
|
|
|
209
208
|
## Report format
|
|
210
209
|
|
|
@@ -245,7 +244,7 @@ Regions with two or more findings — examine these first:
|
|
|
245
244
|
|
|
246
245
|
**Evidence:**
|
|
247
246
|
> Verbatim quote from namespace.yaml, stub, source docstring (via
|
|
248
|
-
> `
|
|
247
|
+
> `uncoded body`), or import statement.
|
|
249
248
|
|
|
250
249
|
One or two sentences describing the inconsistency. Not a diagnosis. Not a fix.
|
|
251
250
|
|
|
@@ -45,9 +45,8 @@ Verify by reading `.uncoded/namespace.yaml` — if it exists and is non-empty,
|
|
|
45
45
|
proceed. If not, stop and tell the user to run `uncoded sync` first; the review
|
|
46
46
|
depends on the index.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
cross-file reference checks.
|
|
48
|
+
The structural sweep uses `uncoded refs` for cross-file reference checks —
|
|
49
|
+
it ships with uncoded itself and is always available when the index is present.
|
|
51
50
|
|
|
52
51
|
## Workflow
|
|
53
52
|
|
|
@@ -57,7 +56,7 @@ The review proceeds in four sweeps, each building on the previous:
|
|
|
57
56
|
2. **Lexical sweep** — read the namespace, look for naming-level inconsistency.
|
|
58
57
|
3. **Promissory sweep** — check each symbol's name / signature / docstring
|
|
59
58
|
for internal disagreement; names and signatures from the stub, docstrings
|
|
60
|
-
via `
|
|
59
|
+
via `uncoded body`.
|
|
61
60
|
4. **Structural sweep** — combine namespace and imports to find boundary and
|
|
62
61
|
shape symptoms.
|
|
63
62
|
|
|
@@ -97,8 +96,7 @@ model the same entity.
|
|
|
97
96
|
|
|
98
97
|
Detection: scan the namespace for symbol clusters with verb or noun overlap.
|
|
99
98
|
Where suspicion arises, check the stub signatures and the source docstrings
|
|
100
|
-
(via
|
|
101
|
-
candidates overlap in meaning.
|
|
99
|
+
(via `uncoded body`) to confirm the candidates overlap in meaning.
|
|
102
100
|
|
|
103
101
|
**Qualifier accretion.** Names carrying modifiers that are fossils of
|
|
104
102
|
iteration: `_new`, `_v2`, `_updated`, `_legacy`, `_real`, `_proper`, `_final`,
|
|
@@ -121,17 +119,18 @@ subtly different meanings — visible as different signatures, different docstri
|
|
|
121
119
|
content, or different domain associations.
|
|
122
120
|
|
|
123
121
|
Detection: identify name collisions in the namespace, then compare signatures
|
|
124
|
-
(from the stubs) and docstrings (via
|
|
125
|
-
|
|
122
|
+
(from the stubs) and docstrings (via `uncoded body`) to see whether the uses
|
|
123
|
+
agree.
|
|
126
124
|
|
|
127
125
|
## Step 3: Promissory sweep
|
|
128
126
|
|
|
129
127
|
Examine each public symbol's name / signature / docstring triple for internal
|
|
130
128
|
disagreement. Load each source file's stub once for the names and signatures
|
|
131
129
|
across that file's symbols. Then, for each non-trivial public symbol (skip
|
|
132
|
-
trivial one-liners and `__init__` with no meaningful body),
|
|
133
|
-
`
|
|
134
|
-
|
|
130
|
+
trivial one-liners and `__init__` with no meaningful body), run
|
|
131
|
+
`uncoded body <name_path> --in <relative_path>` to read the symbol's source.
|
|
132
|
+
The docstring is at the top; the rest of the body is available for any
|
|
133
|
+
finding that needs it.
|
|
135
134
|
|
|
136
135
|
**Name–signature mismatch.** Does the name's verb fit the signature's return? A
|
|
137
136
|
function called `validate_*` that returns the validated object rather than
|
|
@@ -153,19 +152,20 @@ this for Y; use Z instead." These are confessions — someone noticed drift and
|
|
|
153
152
|
documented it rather than fixing it.
|
|
154
153
|
|
|
155
154
|
Quote evidence verbatim. The stub excerpt is the evidence for name and
|
|
156
|
-
signature findings; the docstring
|
|
157
|
-
|
|
155
|
+
signature findings; the docstring read via `uncoded body` is the evidence
|
|
156
|
+
for any docstring-related finding.
|
|
158
157
|
|
|
159
|
-
**When
|
|
160
|
-
|
|
158
|
+
**When confidence needs the body.** Consult the implementation in the body,
|
|
159
|
+
not just the docstring, when a finding's confidence needs it: a
|
|
160
|
+
name–behaviour mismatch the docstring alone doesn't settle, or a defensive
|
|
161
161
|
docstring you want to verify against the body. Targeted to the symbol, no
|
|
162
162
|
offset arithmetic, no risk of over-reading. Never read a whole source file
|
|
163
163
|
during this sweep.
|
|
164
164
|
|
|
165
165
|
## Step 4: Structural sweep
|
|
166
166
|
|
|
167
|
-
Combine the namespace with the import graph and
|
|
168
|
-
reference resolution.
|
|
167
|
+
Combine the namespace with the import graph and `uncoded refs` for
|
|
168
|
+
cross-file reference resolution.
|
|
169
169
|
|
|
170
170
|
**Overgrown public surfaces / god modules.** A module or class whose public
|
|
171
171
|
namespace is much larger than its siblings, or spans obviously different
|
|
@@ -191,8 +191,8 @@ Check systematically, not by spot-check:
|
|
|
191
191
|
2. Cross-reference with stub import sections — any symbol imported by another
|
|
192
192
|
source module is live; remove it from the candidate list. This culls the
|
|
193
193
|
obvious cases cheaply.
|
|
194
|
-
3. For remaining candidates, use
|
|
195
|
-
|
|
194
|
+
3. For remaining candidates, use `uncoded refs <name_path> --in <relative_path>`
|
|
195
|
+
to verify. Empty output confirms zero callers.
|
|
196
196
|
4. Distinguish two sub-cases when reporting:
|
|
197
197
|
- *No callers anywhere* — dead code; highest priority.
|
|
198
198
|
- *Callers only in tests* — the symbol is tested but not used in source;
|
|
@@ -203,8 +203,7 @@ function in the same module where the function's sole body is `return
|
|
|
203
203
|
<constant>`. Both symbols being public exposes an implementation detail
|
|
204
204
|
unnecessarily — only one needs to be public. Detection: use the stubs to find
|
|
205
205
|
public parameterless functions near public constants, then verify each
|
|
206
|
-
candidate body with
|
|
207
|
-
reporting.
|
|
206
|
+
candidate body with `uncoded body` before reporting.
|
|
208
207
|
|
|
209
208
|
## Report format
|
|
210
209
|
|
|
@@ -245,7 +244,7 @@ Regions with two or more findings — examine these first:
|
|
|
245
244
|
|
|
246
245
|
**Evidence:**
|
|
247
246
|
> Verbatim quote from namespace.yaml, stub, source docstring (via
|
|
248
|
-
> `
|
|
247
|
+
> `uncoded body`), or import statement.
|
|
249
248
|
|
|
250
249
|
One or two sentences describing the inconsistency. Not a diagnosis. Not a fix.
|
|
251
250
|
|
|
@@ -3,11 +3,6 @@ repos:
|
|
|
3
3
|
rev: v5.0.0
|
|
4
4
|
hooks:
|
|
5
5
|
- id: trailing-whitespace
|
|
6
|
-
# Serena rewrites .serena/project.yml on MCP server start with its
|
|
7
|
-
# own default-annotated form, which has a trailing space in one
|
|
8
|
-
# comment line. Trimming it here would just trigger a diff on the
|
|
9
|
-
# next session — Serena owns this file's formatting, so exclude it.
|
|
10
|
-
exclude: ^\.serena/project\.yml$
|
|
11
6
|
- id: end-of-file-fixer
|
|
12
7
|
- id: check-yaml
|
|
13
8
|
- id: check-toml
|
|
@@ -11,12 +11,20 @@ src/:
|
|
|
11
11
|
uncoded/:
|
|
12
12
|
__init__.py:
|
|
13
13
|
__version__:
|
|
14
|
+
ast_helpers.py:
|
|
15
|
+
property_kind:
|
|
16
|
+
assign_target_name:
|
|
17
|
+
body.py:
|
|
18
|
+
resolve_body:
|
|
19
|
+
_extract_body:
|
|
14
20
|
cli.py:
|
|
21
|
+
_find_project_root:
|
|
15
22
|
_sync:
|
|
23
|
+
_body:
|
|
24
|
+
_refs:
|
|
16
25
|
main:
|
|
17
26
|
config.py:
|
|
18
27
|
find_pyproject_toml:
|
|
19
|
-
read_project_name:
|
|
20
28
|
read_source_roots:
|
|
21
29
|
read_instruction_files:
|
|
22
30
|
extract.py:
|
|
@@ -29,8 +37,6 @@ src/:
|
|
|
29
37
|
constants:
|
|
30
38
|
classes:
|
|
31
39
|
functions:
|
|
32
|
-
property_kind:
|
|
33
|
-
_assign_target_name:
|
|
34
40
|
extract_module:
|
|
35
41
|
iter_source_files:
|
|
36
42
|
extract_modules:
|
|
@@ -48,17 +54,38 @@ src/:
|
|
|
48
54
|
increase_indent:
|
|
49
55
|
build_map:
|
|
50
56
|
render_map:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
refs.py:
|
|
58
|
+
TY_VERSION:
|
|
59
|
+
Reference:
|
|
60
|
+
rel_path:
|
|
61
|
+
line:
|
|
62
|
+
col:
|
|
63
|
+
_LSPLocation:
|
|
64
|
+
path:
|
|
65
|
+
line:
|
|
66
|
+
character:
|
|
67
|
+
find_refs:
|
|
68
|
+
_query_references:
|
|
69
|
+
_find_root:
|
|
70
|
+
_terminate:
|
|
71
|
+
_to_rel_path:
|
|
72
|
+
_run_exchange:
|
|
73
|
+
_write_message:
|
|
74
|
+
_read_message:
|
|
75
|
+
_read_response:
|
|
76
|
+
_uri_to_path:
|
|
77
|
+
resolver.py:
|
|
78
|
+
NamePath:
|
|
79
|
+
head:
|
|
80
|
+
tail:
|
|
81
|
+
parse:
|
|
82
|
+
__str__:
|
|
83
|
+
SymbolNotFound:
|
|
84
|
+
UnsupportedNamePath:
|
|
85
|
+
resolve_ast_node:
|
|
86
|
+
resolve_name_position:
|
|
87
|
+
resolve_ast_node_from_source:
|
|
88
|
+
_resolve_class_member:
|
|
62
89
|
skill.py:
|
|
63
90
|
SKILL_OUTPUTS:
|
|
64
91
|
LEGACY_SKILL_OUTPUTS:
|
|
@@ -78,7 +105,7 @@ src/:
|
|
|
78
105
|
name:
|
|
79
106
|
annotation:
|
|
80
107
|
value_source:
|
|
81
|
-
|
|
108
|
+
is_pep695_alias:
|
|
82
109
|
StubClass:
|
|
83
110
|
name:
|
|
84
111
|
bases:
|
|
@@ -109,11 +136,63 @@ src/:
|
|
|
109
136
|
sync_file:
|
|
110
137
|
remove_file:
|
|
111
138
|
tests/:
|
|
139
|
+
test_body.py:
|
|
140
|
+
TestResolveBodyTopLevel:
|
|
141
|
+
test_function_without_decorators:
|
|
142
|
+
test_function_with_decorators:
|
|
143
|
+
test_async_function:
|
|
144
|
+
test_class_whole_body:
|
|
145
|
+
test_module_constant_annotated:
|
|
146
|
+
test_module_constant_unannotated:
|
|
147
|
+
test_pep695_type_alias:
|
|
148
|
+
test_overload_returns_last_definition:
|
|
149
|
+
test_scans_past_non_matching_constant:
|
|
150
|
+
test_not_found_raises_body_not_found:
|
|
151
|
+
test_file_not_found_propagates:
|
|
152
|
+
test_syntax_error_propagates:
|
|
153
|
+
TestResolveBodyClassMember:
|
|
154
|
+
test_method:
|
|
155
|
+
test_property_returns_getter_body:
|
|
156
|
+
test_class_attribute_annotated:
|
|
157
|
+
test_class_attribute_unannotated:
|
|
158
|
+
test_scans_past_non_matching_attribute:
|
|
159
|
+
test_skips_non_function_nodes_in_class:
|
|
160
|
+
test_shadowed_class_member_found_in_last_definition:
|
|
161
|
+
test_shadowed_class_member_not_found_in_last_definition:
|
|
162
|
+
test_not_found_in_class:
|
|
163
|
+
TestUnsupportedNamePath:
|
|
164
|
+
SUPPORTED_SHAPES:
|
|
165
|
+
_assert_raises:
|
|
166
|
+
test_three_segment_path:
|
|
167
|
+
test_nested_class_shape:
|
|
168
|
+
test_empty_leading_segment:
|
|
169
|
+
test_empty_trailing_segment:
|
|
170
|
+
test_empty_middle_segment:
|
|
171
|
+
TestResolveAstNode:
|
|
172
|
+
test_returns_function_def_for_top_level_function:
|
|
173
|
+
test_returns_method_node_for_class_member:
|
|
174
|
+
test_raises_body_not_found:
|
|
175
|
+
test_raises_unsupported_name_path:
|
|
176
|
+
test_file_not_found_propagates:
|
|
177
|
+
test_syntax_error_propagates:
|
|
178
|
+
TestResolveNamePosition:
|
|
179
|
+
test_function:
|
|
180
|
+
test_function_decorator_does_not_shift_line:
|
|
181
|
+
test_async_function:
|
|
182
|
+
test_class:
|
|
183
|
+
test_annotated_assignment:
|
|
184
|
+
test_unannotated_assignment:
|
|
185
|
+
test_type_alias:
|
|
186
|
+
test_class_method:
|
|
187
|
+
test_unexpected_node_type_raises_unsupported_name_path:
|
|
188
|
+
TestResolveBodyByteIdentical:
|
|
189
|
+
test_exact_source_returned:
|
|
112
190
|
test_cli.py:
|
|
113
191
|
TestSyncApplyMode:
|
|
114
192
|
test_writes_namespace_map_stubs_and_instruction_file:
|
|
115
193
|
test_idempotent_second_run:
|
|
116
194
|
test_dedupes_when_claude_md_is_symlink_to_agents_md:
|
|
195
|
+
test_instruction_file_outside_project_uses_absolute_path:
|
|
117
196
|
test_error_when_no_pyproject_toml:
|
|
118
197
|
test_error_when_source_root_missing:
|
|
119
198
|
test_error_when_uncoded_section_missing:
|
|
@@ -132,20 +211,38 @@ tests/:
|
|
|
132
211
|
test_sync_subcommand_runs_in_apply_mode:
|
|
133
212
|
test_check_subcommand_runs_in_check_mode:
|
|
134
213
|
test_check_subcommand_returns_zero_on_fresh_index:
|
|
135
|
-
test_setup_subcommand:
|
|
136
214
|
test_no_subcommand_is_an_error:
|
|
137
215
|
test_unknown_subcommand_is_an_error:
|
|
216
|
+
TestBodyCommand:
|
|
217
|
+
test_happy_path_dispatch:
|
|
218
|
+
test_class_method_form:
|
|
219
|
+
test_symbol_not_found_exits_one:
|
|
220
|
+
test_file_not_found_exits_one:
|
|
221
|
+
test_syntax_error_exits_one:
|
|
222
|
+
test_works_without_project_root:
|
|
223
|
+
test_in_path_resolves_relative_to_cwd:
|
|
224
|
+
test_stdout_is_exact_body:
|
|
225
|
+
test_unsupported_name_path_exits_one:
|
|
226
|
+
test_missing_in_flag_exits_with_two:
|
|
227
|
+
TestRefsCommand:
|
|
228
|
+
test_happy_path_dispatch:
|
|
229
|
+
test_class_method_form:
|
|
230
|
+
test_symbol_not_found_exits_one:
|
|
231
|
+
test_file_not_found_exits_one:
|
|
232
|
+
test_syntax_error_exits_one:
|
|
233
|
+
test_works_without_project_root:
|
|
234
|
+
test_in_path_resolves_relative_to_cwd:
|
|
235
|
+
test_unsupported_name_path_exits_one:
|
|
236
|
+
test_missing_in_flag_exits_with_two:
|
|
237
|
+
test_zero_references_exits_zero_with_empty_stdout:
|
|
238
|
+
test_multiple_references_prints_sorted:
|
|
239
|
+
test_lsp_failure_exits_one:
|
|
138
240
|
_init_repo:
|
|
139
241
|
test_config.py:
|
|
140
242
|
TestFindPyprojectToml:
|
|
141
243
|
test_finds_at_start:
|
|
142
244
|
test_finds_in_parent_of_start:
|
|
143
245
|
test_returns_none_if_not_found:
|
|
144
|
-
TestReadProjectName:
|
|
145
|
-
test_reads_name_from_pyproject_toml:
|
|
146
|
-
test_falls_back_to_start_name_when_no_pyproject:
|
|
147
|
-
test_falls_back_to_start_name_when_no_project_section:
|
|
148
|
-
test_falls_back_to_start_name_when_name_missing:
|
|
149
246
|
TestReadSourceRoots:
|
|
150
247
|
test_reads_source_roots:
|
|
151
248
|
test_raises_if_no_uncoded_section:
|
|
@@ -155,7 +252,7 @@ tests/:
|
|
|
155
252
|
test_reads_configured_list:
|
|
156
253
|
test_empty_list_is_respected:
|
|
157
254
|
test_extract.py:
|
|
158
|
-
|
|
255
|
+
TestExtractModuleFromSource:
|
|
159
256
|
test_classes_and_functions:
|
|
160
257
|
test_async_functions_and_methods:
|
|
161
258
|
test_empty_module:
|
|
@@ -163,10 +260,13 @@ tests/:
|
|
|
163
260
|
test_type_alias_classic:
|
|
164
261
|
test_type_alias_pep695:
|
|
165
262
|
test_tuple_unpacking_skipped:
|
|
263
|
+
test_chained_assignment_skipped:
|
|
166
264
|
test_unannotated_class_variable:
|
|
265
|
+
test_class_tuple_unpacking_skipped:
|
|
167
266
|
test_annotated_attributes:
|
|
168
267
|
test_property_classified_as_attribute:
|
|
169
268
|
test_property_setter_and_deleter_suppressed:
|
|
269
|
+
test_non_property_decorator_classified_as_method:
|
|
170
270
|
test_preserves_source_order:
|
|
171
271
|
TestIterAndExtract:
|
|
172
272
|
test_basic_walk:
|
|
@@ -174,7 +274,7 @@ tests/:
|
|
|
174
274
|
test_includes_init_with_symbols:
|
|
175
275
|
test_skips_empty_init:
|
|
176
276
|
test_skips_syntax_errors:
|
|
177
|
-
|
|
277
|
+
TestExtractModulesFromFiles:
|
|
178
278
|
test_returns_module_info_per_parseable_file:
|
|
179
279
|
test_preserves_source_order:
|
|
180
280
|
test_module_with_only_constants_is_kept:
|
|
@@ -215,29 +315,38 @@ tests/:
|
|
|
215
315
|
test_header_appears_at_top:
|
|
216
316
|
test_header_mentions_stub_pointer:
|
|
217
317
|
test_header_does_not_break_yaml_parse:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
318
|
+
test_refs.py:
|
|
319
|
+
TestFindRefs:
|
|
320
|
+
test_returns_empty_for_dead_symbol:
|
|
321
|
+
test_finds_multiple_references_across_files:
|
|
322
|
+
test_class_method_shape:
|
|
323
|
+
test_results_are_sorted:
|
|
324
|
+
test_line_and_col_are_one_indexed:
|
|
325
|
+
test_path_with_spaces_is_not_percent_encoded:
|
|
326
|
+
TestToRelPath:
|
|
327
|
+
test_returns_relative_path_when_under_cwd:
|
|
328
|
+
test_returns_absolute_path_when_outside_cwd:
|
|
329
|
+
TestQueryReferences:
|
|
330
|
+
test_finds_call_sites:
|
|
331
|
+
test_uvx_not_found_raises_runtime_error:
|
|
332
|
+
test_returns_empty_list_when_no_references:
|
|
333
|
+
test_returns_lsp_locations_when_popen_succeeds:
|
|
334
|
+
TestRunExchange:
|
|
335
|
+
test_lsp_error_raises:
|
|
336
|
+
test_empty_result_list_returns_empty:
|
|
337
|
+
TestFindRoot:
|
|
338
|
+
test_returns_pyproject_parent_when_found:
|
|
339
|
+
test_returns_in_path_parent_when_not_found:
|
|
340
|
+
TestTerminate:
|
|
341
|
+
test_kills_on_timeout:
|
|
342
|
+
TestReadMessage:
|
|
343
|
+
test_raises_on_closed_stream:
|
|
344
|
+
test_parses_framed_message:
|
|
345
|
+
TestReadResponse:
|
|
346
|
+
test_skips_notifications_until_matching_id:
|
|
347
|
+
_lsp_stream:
|
|
348
|
+
_init_response:
|
|
349
|
+
_shutdown_response:
|
|
241
350
|
test_skill.py:
|
|
242
351
|
TestSyncSkill:
|
|
243
352
|
test_skill_name_and_output_paths:
|
|
@@ -263,7 +372,7 @@ tests/:
|
|
|
263
372
|
test_class_with_attributes_and_methods:
|
|
264
373
|
test_class_with_bases:
|
|
265
374
|
test_class_no_bases:
|
|
266
|
-
|
|
375
|
+
test_extract_params_covers_input_kind:
|
|
267
376
|
test_imports_collected:
|
|
268
377
|
test_syntax_error_raises:
|
|
269
378
|
test_source_order_preserved:
|
|
@@ -275,6 +384,8 @@ tests/:
|
|
|
275
384
|
test_type_alias_classic:
|
|
276
385
|
test_type_alias_pep695:
|
|
277
386
|
test_tuple_unpacking_skipped:
|
|
387
|
+
test_ann_assign_non_name_target_skipped:
|
|
388
|
+
test_class_tuple_unpacking_skipped:
|
|
278
389
|
test_class_with_unannotated_attribute:
|
|
279
390
|
test_property_rendered_as_attribute:
|
|
280
391
|
test_property_without_return_annotation:
|
|
@@ -284,9 +395,9 @@ tests/:
|
|
|
284
395
|
test_imports_rendered:
|
|
285
396
|
test_rendered_stub_has_no_line_range_comments:
|
|
286
397
|
test_async_function_prefix:
|
|
287
|
-
|
|
398
|
+
test_render_param_covers_input_kind:
|
|
399
|
+
test_return_annotation_rendered:
|
|
288
400
|
test_class_with_bases:
|
|
289
|
-
test_class_no_bases:
|
|
290
401
|
test_class_with_no_members_renders_body:
|
|
291
402
|
test_attribute_with_annotation:
|
|
292
403
|
test_method_indented:
|
|
@@ -298,9 +409,8 @@ tests/:
|
|
|
298
409
|
test_constant_bare_annotation_rendered:
|
|
299
410
|
test_type_alias_pep695_rendered:
|
|
300
411
|
test_unannotated_class_attribute_rendered:
|
|
412
|
+
test_renders_valid_python_for_representative_source:
|
|
301
413
|
TestBuildStubs:
|
|
302
|
-
_setup:
|
|
303
|
-
_build:
|
|
304
414
|
test_writes_expected_stubs:
|
|
305
415
|
test_removes_orphan_stub_when_source_deleted:
|
|
306
416
|
test_removes_orphan_stub_when_source_renamed:
|
|
@@ -309,9 +419,8 @@ tests/:
|
|
|
309
419
|
test_no_op_when_clean:
|
|
310
420
|
test_reports_count_on_first_build:
|
|
311
421
|
test_reports_zero_when_clean:
|
|
422
|
+
test_skips_module_with_no_symbols:
|
|
312
423
|
TestBuildStubsCheckMode:
|
|
313
|
-
_setup:
|
|
314
|
-
_build:
|
|
315
424
|
test_does_not_write_stub_in_check_mode:
|
|
316
425
|
test_zero_changes_when_clean:
|
|
317
426
|
test_detects_stale_stub_content:
|
|
@@ -322,6 +431,9 @@ tests/:
|
|
|
322
431
|
test_prunes_orphan_stubs:
|
|
323
432
|
test_project_root_anchors_writes_independent_of_cwd:
|
|
324
433
|
test_project_root_anchors_orphan_pruning_independent_of_cwd:
|
|
434
|
+
test_source_root_outside_project_root_skips_cleanup:
|
|
435
|
+
_setup:
|
|
436
|
+
_build:
|
|
325
437
|
test_sync.py:
|
|
326
438
|
TestSyncFile:
|
|
327
439
|
test_creates_missing_file:
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# src/uncoded/body.py
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from uncoded.resolver import NamePath, resolve_ast_node_from_source
|
|
6
|
+
|
|
7
|
+
def resolve_body(name_path: NamePath, in_path: Path) -> str:
|
|
8
|
+
...
|
|
9
|
+
|
|
10
|
+
def _extract_body(*, node: ast.stmt, lines: list[str]) -> str:
|
|
11
|
+
...
|
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
import argparse
|
|
4
4
|
import sys
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from uncoded.body import resolve_body
|
|
6
7
|
from uncoded.config import find_pyproject_toml, read_instruction_files, read_source_roots
|
|
7
8
|
from uncoded.extract import extract_modules, iter_source_files
|
|
8
9
|
from uncoded.instruction_files import sync_instruction_file
|
|
9
10
|
from uncoded.namespace_map import build_map, render_map
|
|
10
|
-
from uncoded.
|
|
11
|
+
from uncoded.refs import find_refs
|
|
12
|
+
from uncoded.resolver import NamePath, SymbolNotFound, UnsupportedNamePath
|
|
11
13
|
from uncoded.skill import sync_skill
|
|
12
14
|
from uncoded.stubs import build_stubs
|
|
13
15
|
from uncoded.sync import sync_file
|
|
14
16
|
|
|
17
|
+
def _find_project_root(*, start: Path) -> Path | None:
|
|
18
|
+
...
|
|
19
|
+
|
|
15
20
|
def _sync(*, start: Path | None, check: bool) -> int:
|
|
16
21
|
...
|
|
17
22
|
|
|
23
|
+
def _body(*, name_path: str, in_path: str) -> int:
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
def _refs(*, name_path: str, in_path: str) -> int:
|
|
27
|
+
...
|
|
28
|
+
|
|
18
29
|
def main() -> int:
|
|
19
30
|
...
|