uncoded 0.6.0__tar.gz → 0.7.1__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.6.0 → uncoded-0.7.1}/.agents/skills/coherence-review/SKILL.md +31 -30
- {uncoded-0.6.0 → uncoded-0.7.1}/.claude/skills/coherence-review/SKILL.md +31 -30
- {uncoded-0.6.0 → uncoded-0.7.1}/.serena/project.yml +1 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/namespace.yaml +72 -39
- uncoded-0.7.1/.uncoded/stubs/src/uncoded/cli.pyi +19 -0
- uncoded-0.7.1/.uncoded/stubs/src/uncoded/config.pyi +17 -0
- uncoded-0.7.1/.uncoded/stubs/src/uncoded/extract.pyi +33 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/src/uncoded/instruction_files.pyi +1 -7
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/src/uncoded/namespace_map.pyi +0 -5
- uncoded-0.7.1/.uncoded/stubs/src/uncoded/serena_setup.pyi +26 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/src/uncoded/skill.pyi +1 -2
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/src/uncoded/stubs.pyi +8 -36
- uncoded-0.7.1/.uncoded/stubs/src/uncoded/sync.pyi +9 -0
- uncoded-0.7.1/.uncoded/stubs/tests/test_cli.pyi +83 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_config.pyi +15 -9
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_extract.pyi +24 -7
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_instruction_files.pyi +10 -5
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_namespace_map.pyi +0 -8
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_serena_setup.pyi +14 -22
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_skill.pyi +7 -2
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_stubs.pyi +44 -18
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_sync.pyi +15 -2
- {uncoded-0.6.0 → uncoded-0.7.1}/AGENTS.md +33 -15
- uncoded-0.7.1/CLAUDE.md +1 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/PKG-INFO +63 -14
- {uncoded-0.6.0 → uncoded-0.7.1}/README.md +60 -12
- {uncoded-0.6.0 → uncoded-0.7.1}/pyproject.toml +11 -1
- uncoded-0.7.1/src/uncoded/cli.py +177 -0
- uncoded-0.7.1/src/uncoded/config.py +87 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/extract.py +35 -27
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/instruction_files.py +35 -23
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/namespace_map.py +1 -2
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/serena_setup.py +64 -51
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/skill.py +46 -34
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/stubs.py +112 -70
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/sync.py +32 -9
- uncoded-0.7.1/tests/test_cli.py +432 -0
- uncoded-0.7.1/tests/test_config.py +92 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/test_extract.py +88 -17
- uncoded-0.7.1/tests/test_instruction_files.py +122 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/test_namespace_map.py +0 -31
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/test_serena_setup.py +92 -42
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/test_skill.py +46 -24
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/test_stubs.py +391 -98
- uncoded-0.7.1/tests/test_sync.py +139 -0
- uncoded-0.7.1/uv.lock +329 -0
- uncoded-0.6.0/.uncoded/stubs/src/uncoded/cli.pyi +0 -23
- uncoded-0.6.0/.uncoded/stubs/src/uncoded/config.pyi +0 -17
- uncoded-0.6.0/.uncoded/stubs/src/uncoded/extract.pyi +0 -41
- uncoded-0.6.0/.uncoded/stubs/src/uncoded/serena_setup.pyi +0 -32
- uncoded-0.6.0/.uncoded/stubs/src/uncoded/sync.pyi +0 -11
- uncoded-0.6.0/.uncoded/stubs/tests/test_cli.pyi +0 -66
- uncoded-0.6.0/CLAUDE.md +0 -155
- uncoded-0.6.0/MAINTENANCE.md +0 -26
- uncoded-0.6.0/SYSTEM.md +0 -53
- uncoded-0.6.0/src/uncoded/cli.py +0 -103
- uncoded-0.6.0/src/uncoded/config.py +0 -62
- uncoded-0.6.0/tests/test_cli.py +0 -199
- uncoded-0.6.0/tests/test_config.py +0 -83
- uncoded-0.6.0/tests/test_instruction_files.py +0 -92
- uncoded-0.6.0/tests/test_sync.py +0 -82
- uncoded-0.6.0/uv.lock +0 -229
- {uncoded-0.6.0 → uncoded-0.7.1}/.claude/settings.json +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.github/workflows/ci.yml +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.github/workflows/publish.yml +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.gitignore +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.mcp.json +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.pre-commit-config.yaml +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/reviews/2026-04-25-001215.md +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/src/uncoded/__init__.pyi +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/.uncoded/stubs/tests/test_uncoded.pyi +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/LICENSE +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/resources/lsp-research.md +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/src/uncoded/__init__.py +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/__init__.py +0 -0
- {uncoded-0.6.0 → uncoded-0.7.1}/tests/test_uncoded.py +0 -0
|
@@ -55,8 +55,9 @@ The review proceeds in four sweeps, each building on the previous:
|
|
|
55
55
|
|
|
56
56
|
1. **Orient** — load the navigation index and form a mental map.
|
|
57
57
|
2. **Lexical sweep** — read the namespace, look for naming-level inconsistency.
|
|
58
|
-
3. **Promissory sweep** —
|
|
59
|
-
|
|
58
|
+
3. **Promissory sweep** — check each symbol's name / signature / docstring
|
|
59
|
+
for internal disagreement; names and signatures from the stub, docstrings
|
|
60
|
+
via `find_symbol(include_body=True)`.
|
|
60
61
|
4. **Structural sweep** — combine namespace and imports to find boundary and
|
|
61
62
|
shape symptoms.
|
|
62
63
|
|
|
@@ -66,9 +67,8 @@ until the end.
|
|
|
66
67
|
## Step 1: Orient
|
|
67
68
|
|
|
68
69
|
Read `.uncoded/namespace.yaml` in full. This is the map — directories, files,
|
|
69
|
-
classes, methods, functions
|
|
70
|
-
|
|
71
|
-
evidence.
|
|
70
|
+
classes, methods, functions. Do not skim. Every public symbol in the codebase
|
|
71
|
+
is listed here, and the shape of the namespace itself is evidence.
|
|
72
72
|
|
|
73
73
|
While reading, note:
|
|
74
74
|
|
|
@@ -96,8 +96,9 @@ interchangeably. Two classes called `UserRecord` and `AccountProfile` that
|
|
|
96
96
|
model the same entity.
|
|
97
97
|
|
|
98
98
|
Detection: scan the namespace for symbol clusters with verb or noun overlap.
|
|
99
|
-
Where suspicion arises,
|
|
100
|
-
|
|
99
|
+
Where suspicion arises, check the stub signatures and the source docstrings
|
|
100
|
+
(via Serena's `find_symbol` with `include_body=True`) to confirm the
|
|
101
|
+
candidates overlap in meaning.
|
|
101
102
|
|
|
102
103
|
**Qualifier accretion.** Names carrying modifiers that are fossils of
|
|
103
104
|
iteration: `_new`, `_v2`, `_updated`, `_legacy`, `_real`, `_proper`, `_final`,
|
|
@@ -119,16 +120,18 @@ with the rest of the codebase.
|
|
|
119
120
|
subtly different meanings — visible as different signatures, different docstring
|
|
120
121
|
content, or different domain associations.
|
|
121
122
|
|
|
122
|
-
Detection: identify name collisions in the namespace, then
|
|
123
|
-
|
|
123
|
+
Detection: identify name collisions in the namespace, then compare signatures
|
|
124
|
+
(from the stubs) and docstrings (via Serena's `find_symbol` with
|
|
125
|
+
`include_body=True`) to see whether the uses agree.
|
|
124
126
|
|
|
125
127
|
## Step 3: Promissory sweep
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
Examine each public symbol's name / signature / docstring triple for internal
|
|
130
|
+
disagreement. Load each source file's stub once for the names and signatures
|
|
131
|
+
across that file's symbols. Then, for each non-trivial public symbol (skip
|
|
132
|
+
trivial one-liners and `__init__` with no meaningful body), call Serena's
|
|
133
|
+
`find_symbol` with `include_body=True` to read the docstring — the call also
|
|
134
|
+
returns the body, available if a finding needs it.
|
|
132
135
|
|
|
133
136
|
**Name–signature mismatch.** Does the name's verb fit the signature's return? A
|
|
134
137
|
function called `validate_*` that returns the validated object rather than
|
|
@@ -149,18 +152,15 @@ describe it. "Note: this does not actually X despite the name." "Do not use
|
|
|
149
152
|
this for Y; use Z instead." These are confessions — someone noticed drift and
|
|
150
153
|
documented it rather than fixing it.
|
|
151
154
|
|
|
152
|
-
The stub
|
|
153
|
-
|
|
155
|
+
Quote evidence verbatim. The stub excerpt is the evidence for name and
|
|
156
|
+
signature findings; the docstring returned by `find_symbol` with
|
|
157
|
+
`include_body=True` is the evidence for any docstring-related finding.
|
|
154
158
|
|
|
155
|
-
**When to read
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
the stub alone doesn't confirm it; a defensive docstring you want to verify is
|
|
161
|
-
accurate. Use Serena's `find_symbol` with `include_body=True` — targeted to the
|
|
162
|
-
symbol, no offset arithmetic, no risk of over-reading. Never read a whole source
|
|
163
|
-
file during this sweep.
|
|
159
|
+
**When to read further.** Read the body when a finding's confidence needs it:
|
|
160
|
+
a name–behaviour mismatch the docstring alone doesn't settle, or a defensive
|
|
161
|
+
docstring you want to verify against the body. Targeted to the symbol, no
|
|
162
|
+
offset arithmetic, no risk of over-reading. Never read a whole source file
|
|
163
|
+
during this sweep.
|
|
164
164
|
|
|
165
165
|
## Step 4: Structural sweep
|
|
166
166
|
|
|
@@ -244,7 +244,8 @@ Regions with two or more findings — examine these first:
|
|
|
244
244
|
**Confidence:** high | medium | low
|
|
245
245
|
|
|
246
246
|
**Evidence:**
|
|
247
|
-
> Verbatim quote from namespace.yaml, stub,
|
|
247
|
+
> Verbatim quote from namespace.yaml, stub, source docstring (via
|
|
248
|
+
> `find_symbol`), or import statement.
|
|
248
249
|
|
|
249
250
|
One or two sentences describing the inconsistency. Not a diagnosis. Not a fix.
|
|
250
251
|
|
|
@@ -261,14 +262,14 @@ clear evidence is useful — the human can filter. A dropped finding is not.
|
|
|
261
262
|
|
|
262
263
|
**Confidence is part of the finding, not a gate.**
|
|
263
264
|
|
|
264
|
-
- `high` — the inconsistency is explicit; evidence is directly in the
|
|
265
|
-
namespace
|
|
265
|
+
- `high` — the inconsistency is explicit; evidence is directly in the
|
|
266
|
+
namespace, the stub, or the source docstring
|
|
266
267
|
- `medium` — strongly implied but depends on judgement about intent
|
|
267
268
|
- `low` — pattern-based suspicion that needs human interpretation
|
|
268
269
|
|
|
269
270
|
**Evidence must be verbatim.** Quote the relevant namespace line, stub excerpt,
|
|
270
|
-
or import statement exactly. A finding the human cannot
|
|
271
|
-
than no finding.
|
|
271
|
+
source docstring, or import statement exactly. A finding the human cannot
|
|
272
|
+
quickly verify is worse than no finding.
|
|
272
273
|
|
|
273
274
|
**One finding per inconsistency.** If a single symbol has a name–signature
|
|
274
275
|
mismatch and a docstring–name mismatch, that is two findings on the same
|
|
@@ -55,8 +55,9 @@ The review proceeds in four sweeps, each building on the previous:
|
|
|
55
55
|
|
|
56
56
|
1. **Orient** — load the navigation index and form a mental map.
|
|
57
57
|
2. **Lexical sweep** — read the namespace, look for naming-level inconsistency.
|
|
58
|
-
3. **Promissory sweep** —
|
|
59
|
-
|
|
58
|
+
3. **Promissory sweep** — check each symbol's name / signature / docstring
|
|
59
|
+
for internal disagreement; names and signatures from the stub, docstrings
|
|
60
|
+
via `find_symbol(include_body=True)`.
|
|
60
61
|
4. **Structural sweep** — combine namespace and imports to find boundary and
|
|
61
62
|
shape symptoms.
|
|
62
63
|
|
|
@@ -66,9 +67,8 @@ until the end.
|
|
|
66
67
|
## Step 1: Orient
|
|
67
68
|
|
|
68
69
|
Read `.uncoded/namespace.yaml` in full. This is the map — directories, files,
|
|
69
|
-
classes, methods, functions
|
|
70
|
-
|
|
71
|
-
evidence.
|
|
70
|
+
classes, methods, functions. Do not skim. Every public symbol in the codebase
|
|
71
|
+
is listed here, and the shape of the namespace itself is evidence.
|
|
72
72
|
|
|
73
73
|
While reading, note:
|
|
74
74
|
|
|
@@ -96,8 +96,9 @@ interchangeably. Two classes called `UserRecord` and `AccountProfile` that
|
|
|
96
96
|
model the same entity.
|
|
97
97
|
|
|
98
98
|
Detection: scan the namespace for symbol clusters with verb or noun overlap.
|
|
99
|
-
Where suspicion arises,
|
|
100
|
-
|
|
99
|
+
Where suspicion arises, check the stub signatures and the source docstrings
|
|
100
|
+
(via Serena's `find_symbol` with `include_body=True`) to confirm the
|
|
101
|
+
candidates overlap in meaning.
|
|
101
102
|
|
|
102
103
|
**Qualifier accretion.** Names carrying modifiers that are fossils of
|
|
103
104
|
iteration: `_new`, `_v2`, `_updated`, `_legacy`, `_real`, `_proper`, `_final`,
|
|
@@ -119,16 +120,18 @@ with the rest of the codebase.
|
|
|
119
120
|
subtly different meanings — visible as different signatures, different docstring
|
|
120
121
|
content, or different domain associations.
|
|
121
122
|
|
|
122
|
-
Detection: identify name collisions in the namespace, then
|
|
123
|
-
|
|
123
|
+
Detection: identify name collisions in the namespace, then compare signatures
|
|
124
|
+
(from the stubs) and docstrings (via Serena's `find_symbol` with
|
|
125
|
+
`include_body=True`) to see whether the uses agree.
|
|
124
126
|
|
|
125
127
|
## Step 3: Promissory sweep
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
Examine each public symbol's name / signature / docstring triple for internal
|
|
130
|
+
disagreement. Load each source file's stub once for the names and signatures
|
|
131
|
+
across that file's symbols. Then, for each non-trivial public symbol (skip
|
|
132
|
+
trivial one-liners and `__init__` with no meaningful body), call Serena's
|
|
133
|
+
`find_symbol` with `include_body=True` to read the docstring — the call also
|
|
134
|
+
returns the body, available if a finding needs it.
|
|
132
135
|
|
|
133
136
|
**Name–signature mismatch.** Does the name's verb fit the signature's return? A
|
|
134
137
|
function called `validate_*` that returns the validated object rather than
|
|
@@ -149,18 +152,15 @@ describe it. "Note: this does not actually X despite the name." "Do not use
|
|
|
149
152
|
this for Y; use Z instead." These are confessions — someone noticed drift and
|
|
150
153
|
documented it rather than fixing it.
|
|
151
154
|
|
|
152
|
-
The stub
|
|
153
|
-
|
|
155
|
+
Quote evidence verbatim. The stub excerpt is the evidence for name and
|
|
156
|
+
signature findings; the docstring returned by `find_symbol` with
|
|
157
|
+
`include_body=True` is the evidence for any docstring-related finding.
|
|
154
158
|
|
|
155
|
-
**When to read
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
the stub alone doesn't confirm it; a defensive docstring you want to verify is
|
|
161
|
-
accurate. Use Serena's `find_symbol` with `include_body=True` — targeted to the
|
|
162
|
-
symbol, no offset arithmetic, no risk of over-reading. Never read a whole source
|
|
163
|
-
file during this sweep.
|
|
159
|
+
**When to read further.** Read the body when a finding's confidence needs it:
|
|
160
|
+
a name–behaviour mismatch the docstring alone doesn't settle, or a defensive
|
|
161
|
+
docstring you want to verify against the body. Targeted to the symbol, no
|
|
162
|
+
offset arithmetic, no risk of over-reading. Never read a whole source file
|
|
163
|
+
during this sweep.
|
|
164
164
|
|
|
165
165
|
## Step 4: Structural sweep
|
|
166
166
|
|
|
@@ -244,7 +244,8 @@ Regions with two or more findings — examine these first:
|
|
|
244
244
|
**Confidence:** high | medium | low
|
|
245
245
|
|
|
246
246
|
**Evidence:**
|
|
247
|
-
> Verbatim quote from namespace.yaml, stub,
|
|
247
|
+
> Verbatim quote from namespace.yaml, stub, source docstring (via
|
|
248
|
+
> `find_symbol`), or import statement.
|
|
248
249
|
|
|
249
250
|
One or two sentences describing the inconsistency. Not a diagnosis. Not a fix.
|
|
250
251
|
|
|
@@ -261,14 +262,14 @@ clear evidence is useful — the human can filter. A dropped finding is not.
|
|
|
261
262
|
|
|
262
263
|
**Confidence is part of the finding, not a gate.**
|
|
263
264
|
|
|
264
|
-
- `high` — the inconsistency is explicit; evidence is directly in the
|
|
265
|
-
namespace
|
|
265
|
+
- `high` — the inconsistency is explicit; evidence is directly in the
|
|
266
|
+
namespace, the stub, or the source docstring
|
|
266
267
|
- `medium` — strongly implied but depends on judgement about intent
|
|
267
268
|
- `low` — pattern-based suspicion that needs human interpretation
|
|
268
269
|
|
|
269
270
|
**Evidence must be verbatim.** Quote the relevant namespace line, stub excerpt,
|
|
270
|
-
or import statement exactly. A finding the human cannot
|
|
271
|
-
than no finding.
|
|
271
|
+
source docstring, or import statement exactly. A finding the human cannot
|
|
272
|
+
quickly verify is worse than no finding.
|
|
272
273
|
|
|
273
274
|
**One finding per inconsistency.** If a single symbol has a name–signature
|
|
274
275
|
mismatch and a docstring–name mismatch, that is two findings on the same
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
# Generated by uncoded — do not edit; regeneration overwrites.
|
|
3
3
|
#
|
|
4
4
|
# Pure key hierarchy (no lists, no values); indent to zoom in.
|
|
5
|
-
# Directory keys end with "/".
|
|
6
|
-
# in source order.
|
|
5
|
+
# Directory keys end with "/".
|
|
7
6
|
#
|
|
8
7
|
# For signatures and types, see stubs:
|
|
9
8
|
# src/foo/bar.py → .uncoded/stubs/src/foo/bar.pyi
|
|
@@ -13,11 +12,11 @@ src/:
|
|
|
13
12
|
__init__.py:
|
|
14
13
|
__version__:
|
|
15
14
|
cli.py:
|
|
16
|
-
DEFAULT_MAP_OUTPUT:
|
|
17
15
|
_sync:
|
|
18
16
|
main:
|
|
19
17
|
config.py:
|
|
20
18
|
find_pyproject_toml:
|
|
19
|
+
read_project_name:
|
|
21
20
|
read_source_roots:
|
|
22
21
|
read_instruction_files:
|
|
23
22
|
extract.py:
|
|
@@ -30,18 +29,17 @@ src/:
|
|
|
30
29
|
constants:
|
|
31
30
|
classes:
|
|
32
31
|
functions:
|
|
33
|
-
|
|
32
|
+
property_kind:
|
|
34
33
|
_assign_target_name:
|
|
35
34
|
extract_module:
|
|
36
35
|
iter_source_files:
|
|
37
|
-
|
|
36
|
+
extract_modules:
|
|
38
37
|
instruction_files.py:
|
|
39
38
|
MARKER_START:
|
|
40
39
|
MARKER_END:
|
|
41
40
|
DEFAULT_INSTRUCTION_FILES:
|
|
42
41
|
_SECTION_BODY:
|
|
43
42
|
SECTION:
|
|
44
|
-
generate_section:
|
|
45
43
|
_replace_or_append:
|
|
46
44
|
sync_instruction_file:
|
|
47
45
|
namespace_map.py:
|
|
@@ -51,16 +49,16 @@ src/:
|
|
|
51
49
|
build_map:
|
|
52
50
|
render_map:
|
|
53
51
|
serena_setup.py:
|
|
52
|
+
_Status:
|
|
54
53
|
SERENA_VERSION:
|
|
55
54
|
MCP_SERVER_SERENA:
|
|
56
|
-
|
|
55
|
+
SERENA_PROJECT_FIELDS:
|
|
57
56
|
SERENA_ALLOWED_TOOLS:
|
|
58
57
|
_STATUS_VERB:
|
|
59
|
-
read_project_name:
|
|
60
58
|
_sync_mcp_json:
|
|
61
|
-
|
|
59
|
+
_write_serena_project_if_absent:
|
|
62
60
|
_sync_claude_settings:
|
|
63
|
-
|
|
61
|
+
setup:
|
|
64
62
|
skill.py:
|
|
65
63
|
SKILL_OUTPUTS:
|
|
66
64
|
LEGACY_SKILL_OUTPUTS:
|
|
@@ -68,7 +66,6 @@ src/:
|
|
|
68
66
|
sync_skill:
|
|
69
67
|
stubs.py:
|
|
70
68
|
VALUE_WIDTH_CAP:
|
|
71
|
-
DEFAULT_STUBS_OUTPUT:
|
|
72
69
|
StubParam:
|
|
73
70
|
name:
|
|
74
71
|
annotation:
|
|
@@ -76,17 +73,15 @@ src/:
|
|
|
76
73
|
name:
|
|
77
74
|
params:
|
|
78
75
|
return_annotation:
|
|
79
|
-
docstring_excerpt:
|
|
80
76
|
is_async:
|
|
81
77
|
StubAssignment:
|
|
82
78
|
name:
|
|
83
79
|
annotation:
|
|
84
80
|
value_source:
|
|
85
|
-
|
|
81
|
+
is_pep695_alias:
|
|
86
82
|
StubClass:
|
|
87
83
|
name:
|
|
88
84
|
bases:
|
|
89
|
-
docstring_excerpt:
|
|
90
85
|
attributes:
|
|
91
86
|
methods:
|
|
92
87
|
StubModule:
|
|
@@ -95,7 +90,6 @@ src/:
|
|
|
95
90
|
constants:
|
|
96
91
|
classes:
|
|
97
92
|
functions:
|
|
98
|
-
_first_sentence:
|
|
99
93
|
_extract_params:
|
|
100
94
|
_render_value:
|
|
101
95
|
_extract_assignment:
|
|
@@ -109,6 +103,7 @@ src/:
|
|
|
109
103
|
_render_assignment:
|
|
110
104
|
render_stub:
|
|
111
105
|
_generate_stubs:
|
|
106
|
+
_write_stubs:
|
|
112
107
|
build_stubs:
|
|
113
108
|
sync.py:
|
|
114
109
|
sync_file:
|
|
@@ -118,31 +113,42 @@ tests/:
|
|
|
118
113
|
TestSyncApplyMode:
|
|
119
114
|
test_writes_namespace_map_stubs_and_instruction_file:
|
|
120
115
|
test_idempotent_second_run:
|
|
116
|
+
test_dedupes_when_claude_md_is_symlink_to_agents_md:
|
|
117
|
+
test_instruction_file_outside_project_uses_absolute_path:
|
|
121
118
|
test_error_when_no_pyproject_toml:
|
|
122
119
|
test_error_when_source_root_missing:
|
|
120
|
+
test_error_when_uncoded_section_missing:
|
|
121
|
+
test_skip_warning_emitted_once_per_broken_file:
|
|
122
|
+
test_anchors_reads_and_writes_at_project_root_when_cwd_is_subdir:
|
|
123
|
+
test_artefacts_match_when_run_from_subdir_vs_project_root:
|
|
123
124
|
TestSyncCheckMode:
|
|
124
125
|
test_returns_one_and_does_not_write_on_empty_repo:
|
|
125
126
|
test_returns_zero_when_index_is_up_to_date:
|
|
126
127
|
test_returns_one_when_source_changes_after_sync:
|
|
127
128
|
test_returns_one_when_source_file_deleted:
|
|
128
129
|
test_returns_one_when_instruction_file_drifts:
|
|
130
|
+
test_dedupes_when_claude_md_is_symlink_to_agents_md:
|
|
129
131
|
test_error_still_returns_one:
|
|
130
132
|
TestMainDispatch:
|
|
131
133
|
test_sync_subcommand_runs_in_apply_mode:
|
|
132
134
|
test_check_subcommand_runs_in_check_mode:
|
|
133
135
|
test_check_subcommand_returns_zero_on_fresh_index:
|
|
134
|
-
|
|
136
|
+
test_setup_subcommand:
|
|
135
137
|
test_no_subcommand_is_an_error:
|
|
136
138
|
test_unknown_subcommand_is_an_error:
|
|
137
139
|
_init_repo:
|
|
138
140
|
test_config.py:
|
|
139
141
|
TestFindPyprojectToml:
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
test_finds_at_start:
|
|
143
|
+
test_finds_in_parent_of_start:
|
|
142
144
|
test_returns_none_if_not_found:
|
|
145
|
+
TestReadProjectName:
|
|
146
|
+
test_reads_name_from_pyproject_toml:
|
|
147
|
+
test_falls_back_to_start_name_when_no_pyproject:
|
|
148
|
+
test_falls_back_to_start_name_when_no_project_section:
|
|
149
|
+
test_falls_back_to_start_name_when_name_missing:
|
|
143
150
|
TestReadSourceRoots:
|
|
144
151
|
test_reads_source_roots:
|
|
145
|
-
test_raises_if_no_pyproject_toml:
|
|
146
152
|
test_raises_if_no_uncoded_section:
|
|
147
153
|
TestReadInstructionFiles:
|
|
148
154
|
test_returns_default_when_no_pyproject_toml:
|
|
@@ -150,7 +156,7 @@ tests/:
|
|
|
150
156
|
test_reads_configured_list:
|
|
151
157
|
test_empty_list_is_respected:
|
|
152
158
|
test_extract.py:
|
|
153
|
-
|
|
159
|
+
TestExtractModuleFromSource:
|
|
154
160
|
test_classes_and_functions:
|
|
155
161
|
test_async_functions_and_methods:
|
|
156
162
|
test_empty_module:
|
|
@@ -158,20 +164,27 @@ tests/:
|
|
|
158
164
|
test_type_alias_classic:
|
|
159
165
|
test_type_alias_pep695:
|
|
160
166
|
test_tuple_unpacking_skipped:
|
|
167
|
+
test_chained_assignment_skipped:
|
|
161
168
|
test_unannotated_class_variable:
|
|
162
|
-
|
|
169
|
+
test_class_tuple_unpacking_skipped:
|
|
163
170
|
test_annotated_attributes:
|
|
164
171
|
test_property_classified_as_attribute:
|
|
165
172
|
test_property_setter_and_deleter_suppressed:
|
|
173
|
+
test_non_property_decorator_classified_as_method:
|
|
166
174
|
test_preserves_source_order:
|
|
167
|
-
|
|
175
|
+
TestIterAndExtract:
|
|
168
176
|
test_basic_walk:
|
|
169
177
|
test_nested_subpackage:
|
|
170
178
|
test_includes_init_with_symbols:
|
|
171
179
|
test_skips_empty_init:
|
|
172
180
|
test_skips_syntax_errors:
|
|
181
|
+
TestExtractModulesFromFiles:
|
|
182
|
+
test_returns_module_info_per_parseable_file:
|
|
183
|
+
test_preserves_source_order:
|
|
184
|
+
test_module_with_only_constants_is_kept:
|
|
185
|
+
test_skips_files_with_no_symbols:
|
|
173
186
|
test_instruction_files.py:
|
|
174
|
-
|
|
187
|
+
TestSection:
|
|
175
188
|
test_contains_markers:
|
|
176
189
|
test_markers_in_order:
|
|
177
190
|
test_ends_with_newline:
|
|
@@ -187,6 +200,9 @@ tests/:
|
|
|
187
200
|
test_does_not_create_file:
|
|
188
201
|
test_does_not_update_existing_file:
|
|
189
202
|
test_reports_no_change_when_clean:
|
|
203
|
+
TestSyncInstructionFileProjectRootAnchor:
|
|
204
|
+
test_project_root_anchors_create_independent_of_cwd:
|
|
205
|
+
test_project_root_anchors_update_of_existing_file:
|
|
190
206
|
test_namespace_map.py:
|
|
191
207
|
TestBuildMap:
|
|
192
208
|
test_single_file:
|
|
@@ -195,9 +211,7 @@ tests/:
|
|
|
195
211
|
test_class_with_attributes_and_methods:
|
|
196
212
|
test_function_is_none:
|
|
197
213
|
test_class_with_no_members:
|
|
198
|
-
test_source_order_preserved:
|
|
199
214
|
test_module_level_constants:
|
|
200
|
-
test_constants_precede_classes_and_functions:
|
|
201
215
|
TestRenderMap:
|
|
202
216
|
test_roundtrips_through_yaml:
|
|
203
217
|
test_preserves_insertion_order:
|
|
@@ -208,16 +222,13 @@ tests/:
|
|
|
208
222
|
test_serena_setup.py:
|
|
209
223
|
REPO_ROOT:
|
|
210
224
|
EXPECTED_EXCLUDED_TOOLS:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
test_falls_back_to_cwd_name_when_no_pyproject:
|
|
214
|
-
test_falls_back_to_cwd_name_when_no_project_section:
|
|
215
|
-
test_falls_back_to_cwd_name_when_name_missing:
|
|
216
|
-
TestSetupSerena:
|
|
225
|
+
EXPECTED_MCP_ARGS:
|
|
226
|
+
TestSetup:
|
|
217
227
|
_run:
|
|
218
228
|
test_creates_all_three_files:
|
|
219
229
|
test_mcp_json_is_valid_and_pins_version:
|
|
220
230
|
test_serena_project_yml_uses_ty_and_ignores_uncoded:
|
|
231
|
+
test_serena_project_yml_escapes_yaml_special_chars_in_name:
|
|
221
232
|
test_claude_settings_enables_serena_and_allowlists_tools:
|
|
222
233
|
test_idempotent:
|
|
223
234
|
test_merges_into_existing_mcp_json:
|
|
@@ -225,9 +236,11 @@ tests/:
|
|
|
225
236
|
test_merges_into_existing_claude_settings:
|
|
226
237
|
test_does_not_overwrite_existing_serena_project_yml:
|
|
227
238
|
test_does_not_duplicate_on_second_merge:
|
|
228
|
-
|
|
239
|
+
test_appends_missing_allowed_tool_to_existing_settings:
|
|
240
|
+
test_setup_uses_root_name_when_no_pyproject:
|
|
241
|
+
test_setup_reads_name_from_pyproject:
|
|
229
242
|
TestRepoDogfooding:
|
|
230
|
-
|
|
243
|
+
test_repo_mcp_json_matches_template_contract:
|
|
231
244
|
test_repo_claude_settings_allowlists_every_serena_tool:
|
|
232
245
|
test_repo_serena_project_yml_matches_template_contract:
|
|
233
246
|
test_skill.py:
|
|
@@ -243,6 +256,9 @@ tests/:
|
|
|
243
256
|
test_check_mode_reports_no_change_when_in_sync:
|
|
244
257
|
test_removes_legacy_skill_files:
|
|
245
258
|
test_check_mode_reports_legacy_skill_files_without_removing:
|
|
259
|
+
TestSyncSkillProjectRootAnchor:
|
|
260
|
+
test_project_root_anchors_writes_independent_of_cwd:
|
|
261
|
+
test_project_root_anchors_legacy_removal_independent_of_cwd:
|
|
246
262
|
test_stubs.py:
|
|
247
263
|
TestExtractStub:
|
|
248
264
|
test_simple_function:
|
|
@@ -252,9 +268,7 @@ tests/:
|
|
|
252
268
|
test_class_with_attributes_and_methods:
|
|
253
269
|
test_class_with_bases:
|
|
254
270
|
test_class_no_bases:
|
|
255
|
-
|
|
256
|
-
test_no_docstring:
|
|
257
|
-
test_kwargs_and_varargs:
|
|
271
|
+
test_extract_params_covers_input_kind:
|
|
258
272
|
test_imports_collected:
|
|
259
273
|
test_syntax_error_raises:
|
|
260
274
|
test_source_order_preserved:
|
|
@@ -266,6 +280,8 @@ tests/:
|
|
|
266
280
|
test_type_alias_classic:
|
|
267
281
|
test_type_alias_pep695:
|
|
268
282
|
test_tuple_unpacking_skipped:
|
|
283
|
+
test_ann_assign_non_name_target_skipped:
|
|
284
|
+
test_class_tuple_unpacking_skipped:
|
|
269
285
|
test_class_with_unannotated_attribute:
|
|
270
286
|
test_property_rendered_as_attribute:
|
|
271
287
|
test_property_without_return_annotation:
|
|
@@ -275,10 +291,10 @@ tests/:
|
|
|
275
291
|
test_imports_rendered:
|
|
276
292
|
test_rendered_stub_has_no_line_range_comments:
|
|
277
293
|
test_async_function_prefix:
|
|
278
|
-
|
|
279
|
-
|
|
294
|
+
test_render_param_covers_input_kind:
|
|
295
|
+
test_return_annotation_rendered:
|
|
280
296
|
test_class_with_bases:
|
|
281
|
-
|
|
297
|
+
test_class_with_no_members_renders_body:
|
|
282
298
|
test_attribute_with_annotation:
|
|
283
299
|
test_method_indented:
|
|
284
300
|
test_ends_with_newline:
|
|
@@ -289,8 +305,10 @@ tests/:
|
|
|
289
305
|
test_constant_bare_annotation_rendered:
|
|
290
306
|
test_type_alias_pep695_rendered:
|
|
291
307
|
test_unannotated_class_attribute_rendered:
|
|
308
|
+
test_renders_valid_python_for_representative_source:
|
|
292
309
|
TestBuildStubs:
|
|
293
310
|
_setup:
|
|
311
|
+
_build:
|
|
294
312
|
test_writes_expected_stubs:
|
|
295
313
|
test_removes_orphan_stub_when_source_deleted:
|
|
296
314
|
test_removes_orphan_stub_when_source_renamed:
|
|
@@ -299,12 +317,21 @@ tests/:
|
|
|
299
317
|
test_no_op_when_clean:
|
|
300
318
|
test_reports_count_on_first_build:
|
|
301
319
|
test_reports_zero_when_clean:
|
|
320
|
+
test_skips_module_with_no_symbols:
|
|
302
321
|
TestBuildStubsCheckMode:
|
|
303
322
|
_setup:
|
|
323
|
+
_build:
|
|
304
324
|
test_does_not_write_stub_in_check_mode:
|
|
305
325
|
test_zero_changes_when_clean:
|
|
306
326
|
test_detects_stale_stub_content:
|
|
307
327
|
test_detects_orphan_stub_without_removing_it:
|
|
328
|
+
TestWriteStubs:
|
|
329
|
+
test_writes_stubs:
|
|
330
|
+
test_check_mode_does_not_write:
|
|
331
|
+
test_prunes_orphan_stubs:
|
|
332
|
+
test_project_root_anchors_writes_independent_of_cwd:
|
|
333
|
+
test_project_root_anchors_orphan_pruning_independent_of_cwd:
|
|
334
|
+
test_source_root_outside_project_root_skips_cleanup:
|
|
308
335
|
test_sync.py:
|
|
309
336
|
TestSyncFile:
|
|
310
337
|
test_creates_missing_file:
|
|
@@ -320,6 +347,12 @@ tests/:
|
|
|
320
347
|
test_noop_when_absent:
|
|
321
348
|
test_check_mode_does_not_remove:
|
|
322
349
|
test_check_mode_reports_noop_when_absent:
|
|
350
|
+
TestSyncFileProjectRootAnchor:
|
|
351
|
+
test_project_root_anchors_write_independent_of_cwd:
|
|
352
|
+
test_project_root_preserves_relative_path_in_message:
|
|
353
|
+
test_absolute_path_makes_project_root_a_no_op:
|
|
354
|
+
TestRemoveFileProjectRootAnchor:
|
|
355
|
+
test_project_root_anchors_removal_independent_of_cwd:
|
|
323
356
|
test_uncoded.py:
|
|
324
357
|
test_import:
|
|
325
358
|
test_version_is_exposed:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# src/uncoded/cli.py
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from uncoded.config import find_pyproject_toml, read_instruction_files, read_source_roots
|
|
7
|
+
from uncoded.extract import extract_modules, iter_source_files
|
|
8
|
+
from uncoded.instruction_files import sync_instruction_file
|
|
9
|
+
from uncoded.namespace_map import build_map, render_map
|
|
10
|
+
from uncoded.serena_setup import setup
|
|
11
|
+
from uncoded.skill import sync_skill
|
|
12
|
+
from uncoded.stubs import build_stubs
|
|
13
|
+
from uncoded.sync import sync_file
|
|
14
|
+
|
|
15
|
+
def _sync(*, start: Path | None, check: bool) -> int:
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
def main() -> int:
|
|
19
|
+
...
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# src/uncoded/config.py
|
|
2
|
+
|
|
3
|
+
import tomllib
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from uncoded.instruction_files import DEFAULT_INSTRUCTION_FILES
|
|
6
|
+
|
|
7
|
+
def find_pyproject_toml(start: Path) -> Path | None:
|
|
8
|
+
...
|
|
9
|
+
|
|
10
|
+
def read_project_name(start: Path) -> str:
|
|
11
|
+
...
|
|
12
|
+
|
|
13
|
+
def read_source_roots(pyproject_path: Path) -> list[Path]:
|
|
14
|
+
...
|
|
15
|
+
|
|
16
|
+
def read_instruction_files(start: Path) -> list[Path]:
|
|
17
|
+
...
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# src/uncoded/extract.py
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import sys
|
|
5
|
+
from collections.abc import Iterable, Iterator
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
def property_kind(node: ast.FunctionDef | ast.AsyncFunctionDef) -> str | None:
|
|
10
|
+
...
|
|
11
|
+
|
|
12
|
+
def _assign_target_name(node: ast.Assign | ast.AnnAssign) -> str | None:
|
|
13
|
+
...
|
|
14
|
+
|
|
15
|
+
def extract_module(source: str, rel_path: str) -> ModuleInfo:
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
def iter_source_files(source_root: Path, project_root: Path) -> Iterator[tuple[str, str]]:
|
|
19
|
+
...
|
|
20
|
+
|
|
21
|
+
def extract_modules(files: Iterable[tuple[str, str]]) -> list[ModuleInfo]:
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
class ClassInfo:
|
|
25
|
+
name: str
|
|
26
|
+
attributes: list[str] = field(default_factory=list)
|
|
27
|
+
methods: list[str] = field(default_factory=list)
|
|
28
|
+
|
|
29
|
+
class ModuleInfo:
|
|
30
|
+
rel_path: str
|
|
31
|
+
constants: list[str] = field(default_factory=list)
|
|
32
|
+
classes: list[ClassInfo] = field(default_factory=list)
|
|
33
|
+
functions: list[str] = field(default_factory=list)
|
|
@@ -9,14 +9,8 @@ DEFAULT_INSTRUCTION_FILES = [Path('CLAUDE.md'), Path('AGENTS.md')]
|
|
|
9
9
|
_SECTION_BODY = ...
|
|
10
10
|
SECTION = f'{MARKER_START}\n{_SECTION_BODY}\n{MARKER_END}\n'
|
|
11
11
|
|
|
12
|
-
def generate_section() -> str:
|
|
13
|
-
"""Return the full delimited uncoded section for an instruction file."""
|
|
14
|
-
...
|
|
15
|
-
|
|
16
12
|
def _replace_or_append(existing: str, section: str) -> str:
|
|
17
|
-
"""Replace the delimited section in existing text, or append it if absent."""
|
|
18
13
|
...
|
|
19
14
|
|
|
20
|
-
def sync_instruction_file(path: Path, *, check: bool) -> bool:
|
|
21
|
-
"""Write or update the uncoded navigation section in an instruction file."""
|
|
15
|
+
def sync_instruction_file(path: Path, *, project_root: Path, check: bool) -> bool:
|
|
22
16
|
...
|