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.
Files changed (75) hide show
  1. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/PKG-INFO +71 -10
  2. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/README.md +70 -9
  3. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/pyproject.toml +1 -1
  4. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/__init__.py +6 -1
  5. agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/_version.py +1 -0
  6. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/cli.py +70 -8
  7. agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/formatting.py +476 -0
  8. agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/guidelines.py +968 -0
  9. agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/integration.py +212 -0
  10. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/lsp_server.py +1 -1
  11. agent_codinglanguage_mapper-1.1.1/src/agent_codinglanguage_mapper/templates/opencode/agents/agent-codinglanguage-mapper.md +16 -0
  12. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts +73 -0
  13. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/templates/skill/SKILL.md +11 -2
  14. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/PKG-INFO +71 -10
  15. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/SOURCES.txt +5 -0
  16. agent_codinglanguage_mapper-1.1.1/tests/test_cli.py +85 -0
  17. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_delphi_adapter.py +17 -0
  18. agent_codinglanguage_mapper-1.1.1/tests/test_guideline_formatting.py +342 -0
  19. agent_codinglanguage_mapper-1.1.1/tests/test_guidelines.py +378 -0
  20. agent_codinglanguage_mapper-1.1.1/tests/test_integration_install.py +299 -0
  21. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_lsp_server.py +1 -0
  22. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_opencode_e2e_harness.py +48 -15
  23. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_package_contract.py +23 -2
  24. agent_codinglanguage_mapper-1.0.0/src/agent_codinglanguage_mapper/_version.py +0 -2
  25. agent_codinglanguage_mapper-1.0.0/src/agent_codinglanguage_mapper/integration.py +0 -186
  26. agent_codinglanguage_mapper-1.0.0/tests/test_cli.py +0 -47
  27. agent_codinglanguage_mapper-1.0.0/tests/test_integration_install.py +0 -182
  28. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/LICENSE +0 -0
  29. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/setup.cfg +0 -0
  30. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/__main__.py +0 -0
  31. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/__init__.py +0 -0
  32. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi.py +0 -0
  33. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py +0 -0
  34. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py +0 -0
  35. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py +0 -0
  36. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py +0 -0
  37. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py +0 -0
  38. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py +0 -0
  39. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py +0 -0
  40. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py +0 -0
  41. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py +1 -1
  42. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py +0 -0
  43. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py +0 -0
  44. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py +0 -0
  45. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py +0 -0
  46. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py +0 -0
  47. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py +0 -0
  48. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py +0 -0
  49. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/adapters/tree_sitter.py +0 -0
  50. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/discovery.py +0 -0
  51. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/indexer.py +0 -0
  52. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/lsp_service.py +0 -0
  53. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/mapper.py +0 -0
  54. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/models.py +0 -0
  55. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/protocol.py +0 -0
  56. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/rendering.py +0 -0
  57. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/worker.py +0 -0
  58. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper/workspace.py +0 -0
  59. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/dependency_links.txt +0 -0
  60. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/entry_points.txt +0 -0
  61. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/requires.txt +0 -0
  62. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/src/agent_codinglanguage_mapper.egg-info/top_level.txt +0 -0
  63. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_adapters.py +0 -0
  64. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_discovery.py +0 -0
  65. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_ffi.py +0 -0
  66. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_indexer.py +0 -0
  67. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_language_matrix.py +0 -0
  68. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_large_files.py +0 -0
  69. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_lsp_service.py +0 -0
  70. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_mapper_details.py +0 -0
  71. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_performance_harness.py +0 -0
  72. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_protocol.py +0 -0
  73. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_rendering.py +0 -0
  74. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.1}/tests/test_worker.py +0 -0
  75. {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.0.0
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 packaged skill, plugin, and restricted agent configuration into a repository:
322
+ Install the package-named skill, Markdown agent, and plugin into a repository:
274
323
 
275
324
  ```bash
276
- codinglanguage-mapper opencode install --target . --write
325
+ codinglanguage-mapper opencode install --target .
277
326
  ```
278
327
 
279
328
  This creates:
280
329
 
281
330
  ```text
282
- .agents/skills/mixed-codebase-navigator/SKILL.md
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 `mixed-codebase-navigator` agent denies all tools by default and permits only `skill` and `codebase_map`. 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.
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 mixed-codebase-navigator \
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 six release E2Es: Python, Rust, C#, Delphi, C++, and a mixed-language FFI workspace. They use the pinned local Ornith revision through vLLM 0.23.0 and OpenCode 1.17.18. 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 golden file/line evidence is absent.
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 six scenarios and retain complete evidence:
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 packaged skill, plugin, and restricted agent configuration into a repository:
275
+ Install the package-named skill, Markdown agent, and plugin into a repository:
227
276
 
228
277
  ```bash
229
- codinglanguage-mapper opencode install --target . --write
278
+ codinglanguage-mapper opencode install --target .
230
279
  ```
231
280
 
232
281
  This creates:
233
282
 
234
283
  ```text
235
- .agents/skills/mixed-codebase-navigator/SKILL.md
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 `mixed-codebase-navigator` agent denies all tools by default and permits only `skill` and `codebase_map`. 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.
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 mixed-codebase-navigator \
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 six release E2Es: Python, Rust, C#, Delphi, C++, and a mixed-language FFI workspace. They use the pinned local Ornith revision through vLLM 0.23.0 and OpenCode 1.17.18. 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 golden file/line evidence is absent.
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 six scenarios and retain complete evidence:
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.0.0"
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
-
@@ -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("--write", "--write-config", dest="write_config", action="store_true")
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
- report = _doctor_report(mapper)
153
+ doctor_report = _doctor_report(mapper)
116
154
  if args.format == "json":
117
- print(json.dumps(report, indent=2, sort_keys=True))
155
+ print(json.dumps(doctor_report, indent=2, sort_keys=True))
118
156
  else:
119
- status = "ready" if report["ok"] else "problems"
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: {report['files']}")
123
- print(f"errors: {report['errors']}")
124
- return 0 if report["ok"] else 1
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}")