agent-codinglanguage-mapper 1.0.0__tar.gz → 1.1.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.
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/PKG-INFO +71 -10
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/README.md +70 -9
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/pyproject.toml +1 -1
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/__init__.py +6 -1
- agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/_version.py +1 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/cli.py +70 -8
- agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/formatting.py +476 -0
- agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/guidelines.py +968 -0
- agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/integration.py +212 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/lsp_server.py +1 -1
- agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/templates/opencode/agents/agent-codinglanguage-mapper.md +16 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts +73 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/templates/skill/SKILL.md +11 -2
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/PKG-INFO +71 -10
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/SOURCES.txt +5 -0
- agent_codinglanguage_mapper-1.1.1/tests/test_cli.py +85 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_delphi_adapter.py +17 -0
- agent_codinglanguage_mapper-1.1.1/tests/test_guideline_formatting.py +342 -0
- agent_codinglanguage_mapper-1.1.1/tests/test_guidelines.py +378 -0
- agent_codinglanguage_mapper-1.1.1/tests/test_integration_install.py +299 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_lsp_server.py +1 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_opencode_e2e_harness.py +48 -15
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_package_contract.py +23 -2
- agent_codinglanguage_mapper-1.0.0/src/agent_codinglanguage_mapper/_version.py +0 -2
- agent_codinglanguage_mapper-1.0.0/src/agent_codinglanguage_mapper/integration.py +0 -186
- agent_codinglanguage_mapper-1.0.0/tests/test_cli.py +0 -47
- agent_codinglanguage_mapper-1.0.0/tests/test_integration_install.py +0 -182
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/LICENSE +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/setup.cfg +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/__main__.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/__init__.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py +1 -1
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/tree_sitter.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/discovery.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/indexer.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/lsp_service.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/mapper.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/models.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/protocol.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/rendering.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/worker.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/workspace.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/dependency_links.txt +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/entry_points.txt +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/requires.txt +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/top_level.txt +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_adapters.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_discovery.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_ffi.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_indexer.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_language_matrix.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_large_files.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_lsp_service.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_mapper_details.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_performance_harness.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_protocol.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_rendering.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_worker.py +0 -0
- {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agent-codinglanguage-mapper
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: Agent-focused semantic mapping and language services for mixed-language codebases.
|
|
5
5
|
Author: Dark Light
|
|
6
6
|
License-Expression: MPL-2.0
|
|
@@ -47,7 +47,7 @@ Dynamic: license-file
|
|
|
47
47
|
|
|
48
48
|
# Agent Coding Language Mapper
|
|
49
49
|
|
|
50
|
-
`agent-codinglanguage-mapper` gives coding agents a bounded semantic view of mixed-language repositories. It maps Python, Rust, C#, Delphi, and C++ into one language-neutral index and exposes that index through a Python API, a command-line interface, Protocol 3, an LSP server, and an OpenCode skill/plugin pair.
|
|
50
|
+
`agent-codinglanguage-mapper` gives coding agents a bounded semantic view of mixed-language repositories. It maps Python, Rust, C#, Delphi, and C++ into one language-neutral index and exposes that index through a Python API, a command-line interface, Protocol 3, an LSP server, and an OpenCode skill/plugin pair. It also detects repository coding conventions, audits source against them, and produces reviewable formatting patches before any explicit write.
|
|
51
51
|
|
|
52
52
|
The mapper is designed for code investigation without sending whole files through `grep`, `cat`, or generic file-reading tools. Responses are paginated, carry stable target IDs and source citations, distinguish proven from partial relations, and preserve focus across follow-up requests.
|
|
53
53
|
|
|
@@ -99,6 +99,8 @@ The public types are:
|
|
|
99
99
|
- `Project` and `SourceFile`
|
|
100
100
|
- `Symbol`, `Reference`, and `Relation`
|
|
101
101
|
- `Problem` and `SourceRange`
|
|
102
|
+
- `CodingGuidelines`
|
|
103
|
+
- `GuidelineProfile`, `GuidelineFinding`, `GuidelineChange`, and `GuidelineReport`
|
|
102
104
|
|
|
103
105
|
Parser-native nodes are intentionally private. Ranges are zero-based and half-open. Rendered citations use one-based line numbers, for example `src/payment.py:42`.
|
|
104
106
|
|
|
@@ -124,6 +126,16 @@ codinglanguage-mapper index --root . --out .mapper/index.json
|
|
|
124
126
|
# Discovery and parser diagnostics
|
|
125
127
|
codinglanguage-mapper doctor --root . --format json
|
|
126
128
|
|
|
129
|
+
# Detect and audit repository coding conventions
|
|
130
|
+
codinglanguage-mapper guidelines detect --root . --format json
|
|
131
|
+
codinglanguage-mapper guidelines audit --root . --format json
|
|
132
|
+
|
|
133
|
+
# Preview a deterministic patch; this never changes source files
|
|
134
|
+
codinglanguage-mapper guidelines format --root .
|
|
135
|
+
|
|
136
|
+
# Apply the reviewed plan atomically
|
|
137
|
+
codinglanguage-mapper guidelines format --root . --write
|
|
138
|
+
|
|
127
139
|
# Language Server Protocol over stdio
|
|
128
140
|
codinglanguage-mapper lsp --root .
|
|
129
141
|
|
|
@@ -133,6 +145,43 @@ codinglanguage-mapper worker --root .
|
|
|
133
145
|
|
|
134
146
|
Available view layers are `overview`, `projects`, `languages`, `files`, `file`, `symbols`, `symbol`, `implementation`, `references`, and `problems`.
|
|
135
147
|
|
|
148
|
+
## Coding Guidelines and Formatting
|
|
149
|
+
|
|
150
|
+
The guidelines API uses the mapper's normal project discovery and language detection, so one request can audit a mixed Python, Rust, C#, Delphi, and C++ workspace. Detection is file-specific rather than one profile for the entire repository. Defaults are refined by language configuration and then by the nearest applicable `.editorconfig`, which has the highest precedence.
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from agent_codinglanguage_mapper import CodingGuidelines
|
|
154
|
+
|
|
155
|
+
guidelines = CodingGuidelines.open(".", languages="auto")
|
|
156
|
+
detected = guidelines.detect()
|
|
157
|
+
audit = guidelines.audit()
|
|
158
|
+
|
|
159
|
+
# A stable unified diff for agent or human review; no files are changed.
|
|
160
|
+
patch = guidelines.patch()
|
|
161
|
+
print(patch)
|
|
162
|
+
|
|
163
|
+
# Mutation is rejected unless write=True is explicit.
|
|
164
|
+
plan = guidelines.plan()
|
|
165
|
+
applied = guidelines.apply(plan, write=True)
|
|
166
|
+
print(applied.to_mapping())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`detect()` reports the effective profile and its configuration sources. `audit()` returns exact zero-based, half-open ranges for line length, indentation, line endings, trailing whitespace, and final-newline findings. Invalid supported values and unsupported EditorConfig properties are reported as non-fixable configuration findings; affected rules retain their previous effective value. Agents can use those findings to make source-aware improvements that are outside the formatter's conservative scope. `plan()` records original-content hashes, the guideline-configuration revision, and the exact replacement bytes. `apply()` rejects stale plans after either source or configuration changes, workspace-escaping paths, and symlinks; accepted writes use a same-directory temporary file and atomic replacement.
|
|
170
|
+
|
|
171
|
+
The built-in formatter safely normalizes configured line endings, removes trailing whitespace outside protected multiline string literals, and applies the configured final-newline rule while preserving UTF-8 BOM, UTF-16, and legacy single-byte source encodings. When installed and runnable, the package delegates broader formatting to the language's established tool and validates the result with the mapper before planning it:
|
|
172
|
+
|
|
173
|
+
| Language | Detected configuration | Preferred formatter |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| Python | `pyproject.toml` (`ruff`) and `.editorconfig` | Ruff, then Black |
|
|
176
|
+
| Rust | `rustfmt.toml`, `.rustfmt.toml`, and `.editorconfig` | `rustfmt` |
|
|
177
|
+
| C# | `.editorconfig` common whitespace rules | `dotnet format whitespace` in an isolated temporary copy |
|
|
178
|
+
| Delphi | RAD Studio-compatible defaults and `.editorconfig` | Built-in conservative formatter |
|
|
179
|
+
| C++ | `.clang-format`, `_clang-format`, and `.editorconfig` | `clang-format` |
|
|
180
|
+
|
|
181
|
+
Native formatter executables are optional and are never downloaded or installed by this package. A missing tool selects the built-in formatter. A timeout, nonzero exit, invalid output, or other native failure also falls back to the built-in formatter and emits a structured `native-formatter-failed` finding instead of discarding the audit. No formatter command is executed through a shell.
|
|
182
|
+
|
|
183
|
+
`guidelines audit` exits with status 1 when findings exist, making it suitable for CI. `guidelines format` without `--write` always prints the unified diff and leaves the workspace untouched. The only mutating CLI form is `guidelines format --write`.
|
|
184
|
+
|
|
136
185
|
## Protocol 3
|
|
137
186
|
|
|
138
187
|
Protocol 3 is the bounded request/response contract used by the worker and OpenCode plugin.
|
|
@@ -270,27 +319,37 @@ Example generic client configuration:
|
|
|
270
319
|
|
|
271
320
|
## OpenCode Integration
|
|
272
321
|
|
|
273
|
-
Install the
|
|
322
|
+
Install the package-named skill, Markdown agent, and plugin into a repository:
|
|
274
323
|
|
|
275
324
|
```bash
|
|
276
|
-
codinglanguage-mapper opencode install --target .
|
|
325
|
+
codinglanguage-mapper opencode install --target .
|
|
277
326
|
```
|
|
278
327
|
|
|
279
328
|
This creates:
|
|
280
329
|
|
|
281
330
|
```text
|
|
282
|
-
.agents/skills/
|
|
331
|
+
.agents/skills/agent-codinglanguage-mapper/SKILL.md
|
|
332
|
+
.opencode/agents/agent-codinglanguage-mapper.md
|
|
283
333
|
.opencode/plugins/codebase_map.ts
|
|
284
|
-
opencode.json
|
|
285
334
|
```
|
|
286
335
|
|
|
287
|
-
The generated `
|
|
336
|
+
The generated `agent-codinglanguage-mapper` agent denies all tools by default and permits only its package-named skill, `codebase_map`, and `code_guidelines`. The plugin maps the active OpenCode directory, serializes Protocol 3 requests through one worker, applies a hard timeout, reports bounded worker `stderr`, restarts after failure, and preserves focus plus warm parser indexes across short idle gaps. It stops the worker when the session is deleted or after 60 seconds without another mapper request.
|
|
337
|
+
|
|
338
|
+
The installer never reads or changes `opencode.json`; user configuration remains
|
|
339
|
+
user-owned. The deprecated `--write`, `--write-config`, and `--write-agent`
|
|
340
|
+
compatibility flags are accepted, but the Markdown agent is installed by
|
|
341
|
+
default and those flags do not enable configuration writes.
|
|
342
|
+
|
|
343
|
+
`code_guidelines` exposes four actions: `detect`, `audit`, `patch`, and `apply`. The first three are read-only. `apply` is rejected unless its request contains `write: true`, so the agent must inspect a patch before it can opt into mutation.
|
|
344
|
+
|
|
345
|
+
The agent's YAML frontmatter contains its restricted permissions; no matching
|
|
346
|
+
JSON agent block is required.
|
|
288
347
|
|
|
289
348
|
Run it with:
|
|
290
349
|
|
|
291
350
|
```bash
|
|
292
351
|
opencode run \
|
|
293
|
-
--agent
|
|
352
|
+
--agent agent-codinglanguage-mapper \
|
|
294
353
|
"Find PaymentService, inspect its implementation, and cite the callers. Use only the installed skill and codebase_map."
|
|
295
354
|
```
|
|
296
355
|
|
|
@@ -303,6 +362,8 @@ A typical investigation should:
|
|
|
303
362
|
5. Use `trace` only for explicit Protocol 3 relations.
|
|
304
363
|
6. Follow `next_cursor` when evidence is truncated.
|
|
305
364
|
|
|
365
|
+
A formatting task should first call `code_guidelines` with `detect`, then `audit`, then `patch`. The agent can either improve source-aware findings itself or apply the package plan with `action: apply` and `write: true`. It must finish with another `audit`; it must never use `apply` merely to discover what would change.
|
|
366
|
+
|
|
306
367
|
## Large-Workspace Performance
|
|
307
368
|
|
|
308
369
|
The release benchmark generates one valid file above 100,000 lines for each language and a mixed workspace above 500,000 lines. On the reference Apple Silicon Mac, release budgets are:
|
|
@@ -326,7 +387,7 @@ Private Linux CI records and uploads the same measurements with `--report-only`;
|
|
|
326
387
|
|
|
327
388
|
## Offline Ornith/OpenCode Evaluation
|
|
328
389
|
|
|
329
|
-
The repository contains
|
|
390
|
+
The repository contains seven release E2Es: Python, Rust, C#, Delphi, C++, a mixed-language FFI workspace, and a coding-guidelines write workflow. They use the pinned local Ornith revision through vLLM 0.23.0 and OpenCode 1.17.18. The guidelines scenario must detect and audit the profile, inspect a patch, explicitly apply it with `write: true`, and finish with a clean audit. The Python scenario continues the same session through a headless OpenCode server and must inspect the focused symbol in a second turn without another `find` or explicit `target_id`, proving that the plugin preserves its warm worker. It then opens an independent session whose target-less `inspect` must be empty, proving that focus never crosses chat boundaries. The harness fails if a model shard is missing, a download is attempted, an unapproved tool is called, any assistant message uses a different agent, model, or provider, a worker survives server shutdown, or required evidence is absent.
|
|
330
391
|
|
|
331
392
|
Inspect the plan without launching a model:
|
|
332
393
|
|
|
@@ -340,7 +401,7 @@ Verify the exact local executables, versions, model revision, and weight shards:
|
|
|
340
401
|
python scripts/run_opencode_e2e.py --verify-runtime
|
|
341
402
|
```
|
|
342
403
|
|
|
343
|
-
Run all
|
|
404
|
+
Run all seven scenarios and retain complete evidence:
|
|
344
405
|
|
|
345
406
|
```bash
|
|
346
407
|
HF_HUB_OFFLINE=1 \
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agent Coding Language Mapper
|
|
2
2
|
|
|
3
|
-
`agent-codinglanguage-mapper` gives coding agents a bounded semantic view of mixed-language repositories. It maps Python, Rust, C#, Delphi, and C++ into one language-neutral index and exposes that index through a Python API, a command-line interface, Protocol 3, an LSP server, and an OpenCode skill/plugin pair.
|
|
3
|
+
`agent-codinglanguage-mapper` gives coding agents a bounded semantic view of mixed-language repositories. It maps Python, Rust, C#, Delphi, and C++ into one language-neutral index and exposes that index through a Python API, a command-line interface, Protocol 3, an LSP server, and an OpenCode skill/plugin pair. It also detects repository coding conventions, audits source against them, and produces reviewable formatting patches before any explicit write.
|
|
4
4
|
|
|
5
5
|
The mapper is designed for code investigation without sending whole files through `grep`, `cat`, or generic file-reading tools. Responses are paginated, carry stable target IDs and source citations, distinguish proven from partial relations, and preserve focus across follow-up requests.
|
|
6
6
|
|
|
@@ -52,6 +52,8 @@ The public types are:
|
|
|
52
52
|
- `Project` and `SourceFile`
|
|
53
53
|
- `Symbol`, `Reference`, and `Relation`
|
|
54
54
|
- `Problem` and `SourceRange`
|
|
55
|
+
- `CodingGuidelines`
|
|
56
|
+
- `GuidelineProfile`, `GuidelineFinding`, `GuidelineChange`, and `GuidelineReport`
|
|
55
57
|
|
|
56
58
|
Parser-native nodes are intentionally private. Ranges are zero-based and half-open. Rendered citations use one-based line numbers, for example `src/payment.py:42`.
|
|
57
59
|
|
|
@@ -77,6 +79,16 @@ codinglanguage-mapper index --root . --out .mapper/index.json
|
|
|
77
79
|
# Discovery and parser diagnostics
|
|
78
80
|
codinglanguage-mapper doctor --root . --format json
|
|
79
81
|
|
|
82
|
+
# Detect and audit repository coding conventions
|
|
83
|
+
codinglanguage-mapper guidelines detect --root . --format json
|
|
84
|
+
codinglanguage-mapper guidelines audit --root . --format json
|
|
85
|
+
|
|
86
|
+
# Preview a deterministic patch; this never changes source files
|
|
87
|
+
codinglanguage-mapper guidelines format --root .
|
|
88
|
+
|
|
89
|
+
# Apply the reviewed plan atomically
|
|
90
|
+
codinglanguage-mapper guidelines format --root . --write
|
|
91
|
+
|
|
80
92
|
# Language Server Protocol over stdio
|
|
81
93
|
codinglanguage-mapper lsp --root .
|
|
82
94
|
|
|
@@ -86,6 +98,43 @@ codinglanguage-mapper worker --root .
|
|
|
86
98
|
|
|
87
99
|
Available view layers are `overview`, `projects`, `languages`, `files`, `file`, `symbols`, `symbol`, `implementation`, `references`, and `problems`.
|
|
88
100
|
|
|
101
|
+
## Coding Guidelines and Formatting
|
|
102
|
+
|
|
103
|
+
The guidelines API uses the mapper's normal project discovery and language detection, so one request can audit a mixed Python, Rust, C#, Delphi, and C++ workspace. Detection is file-specific rather than one profile for the entire repository. Defaults are refined by language configuration and then by the nearest applicable `.editorconfig`, which has the highest precedence.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from agent_codinglanguage_mapper import CodingGuidelines
|
|
107
|
+
|
|
108
|
+
guidelines = CodingGuidelines.open(".", languages="auto")
|
|
109
|
+
detected = guidelines.detect()
|
|
110
|
+
audit = guidelines.audit()
|
|
111
|
+
|
|
112
|
+
# A stable unified diff for agent or human review; no files are changed.
|
|
113
|
+
patch = guidelines.patch()
|
|
114
|
+
print(patch)
|
|
115
|
+
|
|
116
|
+
# Mutation is rejected unless write=True is explicit.
|
|
117
|
+
plan = guidelines.plan()
|
|
118
|
+
applied = guidelines.apply(plan, write=True)
|
|
119
|
+
print(applied.to_mapping())
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`detect()` reports the effective profile and its configuration sources. `audit()` returns exact zero-based, half-open ranges for line length, indentation, line endings, trailing whitespace, and final-newline findings. Invalid supported values and unsupported EditorConfig properties are reported as non-fixable configuration findings; affected rules retain their previous effective value. Agents can use those findings to make source-aware improvements that are outside the formatter's conservative scope. `plan()` records original-content hashes, the guideline-configuration revision, and the exact replacement bytes. `apply()` rejects stale plans after either source or configuration changes, workspace-escaping paths, and symlinks; accepted writes use a same-directory temporary file and atomic replacement.
|
|
123
|
+
|
|
124
|
+
The built-in formatter safely normalizes configured line endings, removes trailing whitespace outside protected multiline string literals, and applies the configured final-newline rule while preserving UTF-8 BOM, UTF-16, and legacy single-byte source encodings. When installed and runnable, the package delegates broader formatting to the language's established tool and validates the result with the mapper before planning it:
|
|
125
|
+
|
|
126
|
+
| Language | Detected configuration | Preferred formatter |
|
|
127
|
+
| --- | --- | --- |
|
|
128
|
+
| Python | `pyproject.toml` (`ruff`) and `.editorconfig` | Ruff, then Black |
|
|
129
|
+
| Rust | `rustfmt.toml`, `.rustfmt.toml`, and `.editorconfig` | `rustfmt` |
|
|
130
|
+
| C# | `.editorconfig` common whitespace rules | `dotnet format whitespace` in an isolated temporary copy |
|
|
131
|
+
| Delphi | RAD Studio-compatible defaults and `.editorconfig` | Built-in conservative formatter |
|
|
132
|
+
| C++ | `.clang-format`, `_clang-format`, and `.editorconfig` | `clang-format` |
|
|
133
|
+
|
|
134
|
+
Native formatter executables are optional and are never downloaded or installed by this package. A missing tool selects the built-in formatter. A timeout, nonzero exit, invalid output, or other native failure also falls back to the built-in formatter and emits a structured `native-formatter-failed` finding instead of discarding the audit. No formatter command is executed through a shell.
|
|
135
|
+
|
|
136
|
+
`guidelines audit` exits with status 1 when findings exist, making it suitable for CI. `guidelines format` without `--write` always prints the unified diff and leaves the workspace untouched. The only mutating CLI form is `guidelines format --write`.
|
|
137
|
+
|
|
89
138
|
## Protocol 3
|
|
90
139
|
|
|
91
140
|
Protocol 3 is the bounded request/response contract used by the worker and OpenCode plugin.
|
|
@@ -223,27 +272,37 @@ Example generic client configuration:
|
|
|
223
272
|
|
|
224
273
|
## OpenCode Integration
|
|
225
274
|
|
|
226
|
-
Install the
|
|
275
|
+
Install the package-named skill, Markdown agent, and plugin into a repository:
|
|
227
276
|
|
|
228
277
|
```bash
|
|
229
|
-
codinglanguage-mapper opencode install --target .
|
|
278
|
+
codinglanguage-mapper opencode install --target .
|
|
230
279
|
```
|
|
231
280
|
|
|
232
281
|
This creates:
|
|
233
282
|
|
|
234
283
|
```text
|
|
235
|
-
.agents/skills/
|
|
284
|
+
.agents/skills/agent-codinglanguage-mapper/SKILL.md
|
|
285
|
+
.opencode/agents/agent-codinglanguage-mapper.md
|
|
236
286
|
.opencode/plugins/codebase_map.ts
|
|
237
|
-
opencode.json
|
|
238
287
|
```
|
|
239
288
|
|
|
240
|
-
The generated `
|
|
289
|
+
The generated `agent-codinglanguage-mapper` agent denies all tools by default and permits only its package-named skill, `codebase_map`, and `code_guidelines`. The plugin maps the active OpenCode directory, serializes Protocol 3 requests through one worker, applies a hard timeout, reports bounded worker `stderr`, restarts after failure, and preserves focus plus warm parser indexes across short idle gaps. It stops the worker when the session is deleted or after 60 seconds without another mapper request.
|
|
290
|
+
|
|
291
|
+
The installer never reads or changes `opencode.json`; user configuration remains
|
|
292
|
+
user-owned. The deprecated `--write`, `--write-config`, and `--write-agent`
|
|
293
|
+
compatibility flags are accepted, but the Markdown agent is installed by
|
|
294
|
+
default and those flags do not enable configuration writes.
|
|
295
|
+
|
|
296
|
+
`code_guidelines` exposes four actions: `detect`, `audit`, `patch`, and `apply`. The first three are read-only. `apply` is rejected unless its request contains `write: true`, so the agent must inspect a patch before it can opt into mutation.
|
|
297
|
+
|
|
298
|
+
The agent's YAML frontmatter contains its restricted permissions; no matching
|
|
299
|
+
JSON agent block is required.
|
|
241
300
|
|
|
242
301
|
Run it with:
|
|
243
302
|
|
|
244
303
|
```bash
|
|
245
304
|
opencode run \
|
|
246
|
-
--agent
|
|
305
|
+
--agent agent-codinglanguage-mapper \
|
|
247
306
|
"Find PaymentService, inspect its implementation, and cite the callers. Use only the installed skill and codebase_map."
|
|
248
307
|
```
|
|
249
308
|
|
|
@@ -256,6 +315,8 @@ A typical investigation should:
|
|
|
256
315
|
5. Use `trace` only for explicit Protocol 3 relations.
|
|
257
316
|
6. Follow `next_cursor` when evidence is truncated.
|
|
258
317
|
|
|
318
|
+
A formatting task should first call `code_guidelines` with `detect`, then `audit`, then `patch`. The agent can either improve source-aware findings itself or apply the package plan with `action: apply` and `write: true`. It must finish with another `audit`; it must never use `apply` merely to discover what would change.
|
|
319
|
+
|
|
259
320
|
## Large-Workspace Performance
|
|
260
321
|
|
|
261
322
|
The release benchmark generates one valid file above 100,000 lines for each language and a mixed workspace above 500,000 lines. On the reference Apple Silicon Mac, release budgets are:
|
|
@@ -279,7 +340,7 @@ Private Linux CI records and uploads the same measurements with `--report-only`;
|
|
|
279
340
|
|
|
280
341
|
## Offline Ornith/OpenCode Evaluation
|
|
281
342
|
|
|
282
|
-
The repository contains
|
|
343
|
+
The repository contains seven release E2Es: Python, Rust, C#, Delphi, C++, a mixed-language FFI workspace, and a coding-guidelines write workflow. They use the pinned local Ornith revision through vLLM 0.23.0 and OpenCode 1.17.18. The guidelines scenario must detect and audit the profile, inspect a patch, explicitly apply it with `write: true`, and finish with a clean audit. The Python scenario continues the same session through a headless OpenCode server and must inspect the focused symbol in a second turn without another `find` or explicit `target_id`, proving that the plugin preserves its warm worker. It then opens an independent session whose target-less `inspect` must be empty, proving that focus never crosses chat boundaries. The harness fails if a model shard is missing, a download is attempted, an unapproved tool is called, any assistant message uses a different agent, model, or provider, a worker survives server shutdown, or required evidence is absent.
|
|
283
344
|
|
|
284
345
|
Inspect the plan without launching a model:
|
|
285
346
|
|
|
@@ -293,7 +354,7 @@ Verify the exact local executables, versions, model revision, and weight shards:
|
|
|
293
354
|
python scripts/run_opencode_e2e.py --verify-runtime
|
|
294
355
|
```
|
|
295
356
|
|
|
296
|
-
Run all
|
|
357
|
+
Run all seven scenarios and retain complete evidence:
|
|
297
358
|
|
|
298
359
|
```bash
|
|
299
360
|
HF_HUB_OFFLINE=1 \
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agent-codinglanguage-mapper"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.1.1"
|
|
8
8
|
description = "Agent-focused semantic mapping and language services for mixed-language codebases."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10,<3.15"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from ._version import __version__
|
|
2
|
+
from .guidelines import CodingGuidelines, GuidelineChange, GuidelineFinding, GuidelineProfile, GuidelineReport
|
|
2
3
|
from .mapper import CodebaseMapper
|
|
3
4
|
from .models import Language, Problem, Project, Reference, Relation, SourceFile, SourceRange, Symbol
|
|
4
5
|
from .protocol import AgentRequest, AgentResponse
|
|
@@ -7,6 +8,11 @@ __all__ = [
|
|
|
7
8
|
"AgentRequest",
|
|
8
9
|
"AgentResponse",
|
|
9
10
|
"CodebaseMapper",
|
|
11
|
+
"CodingGuidelines",
|
|
12
|
+
"GuidelineChange",
|
|
13
|
+
"GuidelineFinding",
|
|
14
|
+
"GuidelineProfile",
|
|
15
|
+
"GuidelineReport",
|
|
10
16
|
"Language",
|
|
11
17
|
"Problem",
|
|
12
18
|
"Project",
|
|
@@ -17,4 +23,3 @@ __all__ = [
|
|
|
17
23
|
"Symbol",
|
|
18
24
|
"__version__",
|
|
19
25
|
]
|
|
20
|
-
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.1.1"
|
|
@@ -5,8 +5,9 @@ import json
|
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Sequence
|
|
8
|
+
from typing import BinaryIO, Sequence, TextIO, cast
|
|
9
9
|
|
|
10
|
+
from .guidelines import CodingGuidelines, GuidelineReport
|
|
10
11
|
from .integration import install_opencode, install_skill
|
|
11
12
|
from .mapper import CodebaseMapper
|
|
12
13
|
from .models import Language
|
|
@@ -59,6 +60,18 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
59
60
|
_root_argument(worker)
|
|
60
61
|
worker.add_argument("--project-file", type=Path)
|
|
61
62
|
|
|
63
|
+
guidelines = subparsers.add_parser("guidelines", help="Detect, audit, and apply coding guidelines.")
|
|
64
|
+
guideline_subparsers = guidelines.add_subparsers(dest="guidelines_command", required=True)
|
|
65
|
+
for name in ("detect", "audit"):
|
|
66
|
+
command = guideline_subparsers.add_parser(name)
|
|
67
|
+
_root_argument(command)
|
|
68
|
+
command.add_argument("--format", choices=("json", "text"), default="text")
|
|
69
|
+
command.add_argument("--language", dest="languages", action="append", choices=[item.value for item in Language])
|
|
70
|
+
guideline_format = guideline_subparsers.add_parser("format")
|
|
71
|
+
_root_argument(guideline_format)
|
|
72
|
+
guideline_format.add_argument("--language", dest="languages", action="append", choices=[item.value for item in Language])
|
|
73
|
+
guideline_format.add_argument("--write", action="store_true")
|
|
74
|
+
|
|
62
75
|
skill = subparsers.add_parser("skill", help="Install agent skills.")
|
|
63
76
|
skill_subparsers = skill.add_subparsers(dest="skill_command", required=True)
|
|
64
77
|
skill_install = skill_subparsers.add_parser("install")
|
|
@@ -71,7 +84,14 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
71
84
|
opencode_install.add_argument("--target", type=Path, default=Path("."))
|
|
72
85
|
opencode_install.add_argument("--python", default=sys.executable)
|
|
73
86
|
opencode_install.add_argument("--force", action="store_true")
|
|
74
|
-
opencode_install.add_argument(
|
|
87
|
+
opencode_install.add_argument(
|
|
88
|
+
"--write-agent",
|
|
89
|
+
"--write",
|
|
90
|
+
"--write-config",
|
|
91
|
+
dest="write_config",
|
|
92
|
+
action="store_true",
|
|
93
|
+
help="deprecated compatibility flag; the Markdown agent is always installed",
|
|
94
|
+
)
|
|
75
95
|
return parser
|
|
76
96
|
|
|
77
97
|
|
|
@@ -85,6 +105,24 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
85
105
|
return 0
|
|
86
106
|
if args.command == "worker":
|
|
87
107
|
return serve_worker(args.root, sys.stdin, sys.stdout)
|
|
108
|
+
if args.command == "guidelines":
|
|
109
|
+
languages = tuple(Language(item) for item in (args.languages or ()))
|
|
110
|
+
selection: str | tuple[Language, ...] = languages or "auto"
|
|
111
|
+
guidelines = CodingGuidelines.open(args.root, languages=selection)
|
|
112
|
+
if args.guidelines_command == "detect":
|
|
113
|
+
guideline_report = guidelines.detect()
|
|
114
|
+
_print_guideline_report(guideline_report, args.format)
|
|
115
|
+
return 0
|
|
116
|
+
if args.guidelines_command == "audit":
|
|
117
|
+
guideline_report = guidelines.audit()
|
|
118
|
+
_print_guideline_report(guideline_report, args.format)
|
|
119
|
+
return 1 if guideline_report.findings else 0
|
|
120
|
+
if not args.write:
|
|
121
|
+
_write_patch(guidelines.patch())
|
|
122
|
+
return 0
|
|
123
|
+
guideline_report = guidelines.apply(write=True)
|
|
124
|
+
print(json.dumps(guideline_report.to_mapping(), indent=2, sort_keys=True))
|
|
125
|
+
return 0
|
|
88
126
|
if args.command == "skill":
|
|
89
127
|
path = install_skill(args.target, force=args.force)
|
|
90
128
|
print(path)
|
|
@@ -112,16 +150,27 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
112
150
|
path = write_index(mapper, args.out)
|
|
113
151
|
print(json.dumps({"path": str(path), "revision": mapper.snapshot.revision}, sort_keys=True))
|
|
114
152
|
return 0
|
|
115
|
-
|
|
153
|
+
doctor_report = _doctor_report(mapper)
|
|
116
154
|
if args.format == "json":
|
|
117
|
-
print(json.dumps(
|
|
155
|
+
print(json.dumps(doctor_report, indent=2, sort_keys=True))
|
|
118
156
|
else:
|
|
119
|
-
status = "ready" if
|
|
157
|
+
status = "ready" if doctor_report["ok"] else "problems"
|
|
120
158
|
print(f"status: {status}")
|
|
121
159
|
print("languages: " + ", ".join(item.value for item in Language))
|
|
122
|
-
print(f"files: {
|
|
123
|
-
print(f"errors: {
|
|
124
|
-
|
|
160
|
+
print(f"files: {doctor_report['files']}")
|
|
161
|
+
print(f"errors: {doctor_report['errors']}")
|
|
162
|
+
return 0 if doctor_report["ok"] else 1
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _write_patch(patch: str, stream: TextIO | None = None) -> None:
|
|
166
|
+
output = stream or sys.stdout
|
|
167
|
+
binary = getattr(output, "buffer", None)
|
|
168
|
+
if binary is None:
|
|
169
|
+
output.write(patch)
|
|
170
|
+
output.flush()
|
|
171
|
+
return
|
|
172
|
+
cast(BinaryIO, binary).write(patch.encode("utf-8"))
|
|
173
|
+
cast(BinaryIO, binary).flush()
|
|
125
174
|
|
|
126
175
|
|
|
127
176
|
def _doctor_report(mapper: CodebaseMapper) -> dict[str, object]:
|
|
@@ -136,3 +185,16 @@ def _doctor_report(mapper: CodebaseMapper) -> dict[str, object]:
|
|
|
136
185
|
"problems": len(mapper.snapshot.problems),
|
|
137
186
|
"errors": len(errors),
|
|
138
187
|
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _print_guideline_report(report: GuidelineReport, output_format: str) -> None:
|
|
191
|
+
if output_format == "json":
|
|
192
|
+
print(json.dumps(report.to_mapping(), indent=2, sort_keys=True))
|
|
193
|
+
return
|
|
194
|
+
print(f"workspace: {report.workspace}")
|
|
195
|
+
print(f"profiles: {len(report.profiles)}")
|
|
196
|
+
print(f"findings: {len(report.findings)}")
|
|
197
|
+
for finding in report.findings:
|
|
198
|
+
line = finding.range.start_line + 1
|
|
199
|
+
character = finding.range.start_character + 1
|
|
200
|
+
print(f"{finding.range.path}:{line}:{character}: {finding.severity} {finding.code}: {finding.message}")
|