agent-codinglanguage-mapper 1.0.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/PKG-INFO +69 -5
  2. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/README.md +68 -4
  3. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/pyproject.toml +1 -1
  4. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/__init__.py +6 -1
  5. agent_codinglanguage_mapper-1.1.0/src/agent_codinglanguage_mapper/_version.py +1 -0
  6. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/cli.py +62 -7
  7. agent_codinglanguage_mapper-1.1.0/src/agent_codinglanguage_mapper/formatting.py +476 -0
  8. agent_codinglanguage_mapper-1.1.0/src/agent_codinglanguage_mapper/guidelines.py +968 -0
  9. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/integration.py +1 -0
  10. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/lsp_server.py +1 -1
  11. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts +73 -0
  12. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/templates/skill/SKILL.md +10 -1
  13. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper.egg-info/PKG-INFO +69 -5
  14. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper.egg-info/SOURCES.txt +4 -0
  15. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_cli.py +37 -1
  16. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_delphi_adapter.py +17 -0
  17. agent_codinglanguage_mapper-1.1.0/tests/test_guideline_formatting.py +342 -0
  18. agent_codinglanguage_mapper-1.1.0/tests/test_guidelines.py +378 -0
  19. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_integration_install.py +14 -0
  20. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_lsp_server.py +1 -0
  21. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_opencode_e2e_harness.py +38 -5
  22. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_package_contract.py +23 -2
  23. agent_codinglanguage_mapper-1.0.0/src/agent_codinglanguage_mapper/_version.py +0 -2
  24. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/LICENSE +0 -0
  25. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/setup.cfg +0 -0
  26. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/__main__.py +0 -0
  27. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/__init__.py +0 -0
  28. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi.py +0 -0
  29. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py +0 -0
  30. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py +0 -0
  31. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py +0 -0
  32. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py +0 -0
  33. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py +0 -0
  34. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py +0 -0
  35. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py +0 -0
  36. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py +0 -0
  37. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py +1 -1
  38. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py +0 -0
  39. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py +0 -0
  40. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py +0 -0
  41. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py +0 -0
  42. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py +0 -0
  43. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py +0 -0
  44. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py +0 -0
  45. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/adapters/tree_sitter.py +0 -0
  46. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/discovery.py +0 -0
  47. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/indexer.py +0 -0
  48. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/lsp_service.py +0 -0
  49. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/mapper.py +0 -0
  50. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/models.py +0 -0
  51. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/protocol.py +0 -0
  52. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/rendering.py +0 -0
  53. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/worker.py +0 -0
  54. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper/workspace.py +0 -0
  55. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper.egg-info/dependency_links.txt +0 -0
  56. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper.egg-info/entry_points.txt +0 -0
  57. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper.egg-info/requires.txt +0 -0
  58. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/src/agent_codinglanguage_mapper.egg-info/top_level.txt +0 -0
  59. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_adapters.py +0 -0
  60. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_discovery.py +0 -0
  61. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_ffi.py +0 -0
  62. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_indexer.py +0 -0
  63. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_language_matrix.py +0 -0
  64. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_large_files.py +0 -0
  65. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_lsp_service.py +0 -0
  66. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_mapper_details.py +0 -0
  67. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_performance_harness.py +0 -0
  68. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_protocol.py +0 -0
  69. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_rendering.py +0 -0
  70. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/tests/test_worker.py +0 -0
  71. {agent_codinglanguage_mapper-1.0.0 → agent_codinglanguage_mapper-1.1.0}/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.0
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.
@@ -284,7 +333,20 @@ This creates:
284
333
  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 `mixed-codebase-navigator` agent denies all tools by default and permits only `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
+ `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.
339
+
340
+ ```json
341
+ {
342
+ "permission": {
343
+ "*": "deny",
344
+ "skill": "allow",
345
+ "codebase_map": "allow",
346
+ "code_guidelines": "allow"
347
+ }
348
+ }
349
+ ```
288
350
 
289
351
  Run it with:
290
352
 
@@ -303,6 +365,8 @@ A typical investigation should:
303
365
  5. Use `trace` only for explicit Protocol 3 relations.
304
366
  6. Follow `next_cursor` when evidence is truncated.
305
367
 
368
+ 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.
369
+
306
370
  ## Large-Workspace Performance
307
371
 
308
372
  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 +390,7 @@ Private Linux CI records and uploads the same measurements with `--report-only`;
326
390
 
327
391
  ## Offline Ornith/OpenCode Evaluation
328
392
 
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.
393
+ 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
394
 
331
395
  Inspect the plan without launching a model:
332
396
 
@@ -340,7 +404,7 @@ Verify the exact local executables, versions, model revision, and weight shards:
340
404
  python scripts/run_opencode_e2e.py --verify-runtime
341
405
  ```
342
406
 
343
- Run all six scenarios and retain complete evidence:
407
+ Run all seven scenarios and retain complete evidence:
344
408
 
345
409
  ```bash
346
410
  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.
@@ -237,7 +286,20 @@ This creates:
237
286
  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 `mixed-codebase-navigator` agent denies all tools by default and permits only `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
+ `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.
292
+
293
+ ```json
294
+ {
295
+ "permission": {
296
+ "*": "deny",
297
+ "skill": "allow",
298
+ "codebase_map": "allow",
299
+ "code_guidelines": "allow"
300
+ }
301
+ }
302
+ ```
241
303
 
242
304
  Run it with:
243
305
 
@@ -256,6 +318,8 @@ A typical investigation should:
256
318
  5. Use `trace` only for explicit Protocol 3 relations.
257
319
  6. Follow `next_cursor` when evidence is truncated.
258
320
 
321
+ 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.
322
+
259
323
  ## Large-Workspace Performance
260
324
 
261
325
  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 +343,7 @@ Private Linux CI records and uploads the same measurements with `--report-only`;
279
343
 
280
344
  ## Offline Ornith/OpenCode Evaluation
281
345
 
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.
346
+ 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
347
 
284
348
  Inspect the plan without launching a model:
285
349
 
@@ -293,7 +357,7 @@ Verify the exact local executables, versions, model revision, and weight shards:
293
357
  python scripts/run_opencode_e2e.py --verify-runtime
294
358
  ```
295
359
 
296
- Run all six scenarios and retain complete evidence:
360
+ Run all seven scenarios and retain complete evidence:
297
361
 
298
362
  ```bash
299
363
  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.0"
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")
@@ -85,6 +98,24 @@ def main(argv: Sequence[str] | None = None) -> int:
85
98
  return 0
86
99
  if args.command == "worker":
87
100
  return serve_worker(args.root, sys.stdin, sys.stdout)
101
+ if args.command == "guidelines":
102
+ languages = tuple(Language(item) for item in (args.languages or ()))
103
+ selection: str | tuple[Language, ...] = languages or "auto"
104
+ guidelines = CodingGuidelines.open(args.root, languages=selection)
105
+ if args.guidelines_command == "detect":
106
+ guideline_report = guidelines.detect()
107
+ _print_guideline_report(guideline_report, args.format)
108
+ return 0
109
+ if args.guidelines_command == "audit":
110
+ guideline_report = guidelines.audit()
111
+ _print_guideline_report(guideline_report, args.format)
112
+ return 1 if guideline_report.findings else 0
113
+ if not args.write:
114
+ _write_patch(guidelines.patch())
115
+ return 0
116
+ guideline_report = guidelines.apply(write=True)
117
+ print(json.dumps(guideline_report.to_mapping(), indent=2, sort_keys=True))
118
+ return 0
88
119
  if args.command == "skill":
89
120
  path = install_skill(args.target, force=args.force)
90
121
  print(path)
@@ -112,16 +143,27 @@ def main(argv: Sequence[str] | None = None) -> int:
112
143
  path = write_index(mapper, args.out)
113
144
  print(json.dumps({"path": str(path), "revision": mapper.snapshot.revision}, sort_keys=True))
114
145
  return 0
115
- report = _doctor_report(mapper)
146
+ doctor_report = _doctor_report(mapper)
116
147
  if args.format == "json":
117
- print(json.dumps(report, indent=2, sort_keys=True))
148
+ print(json.dumps(doctor_report, indent=2, sort_keys=True))
118
149
  else:
119
- status = "ready" if report["ok"] else "problems"
150
+ status = "ready" if doctor_report["ok"] else "problems"
120
151
  print(f"status: {status}")
121
152
  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
153
+ print(f"files: {doctor_report['files']}")
154
+ print(f"errors: {doctor_report['errors']}")
155
+ return 0 if doctor_report["ok"] else 1
156
+
157
+
158
+ def _write_patch(patch: str, stream: TextIO | None = None) -> None:
159
+ output = stream or sys.stdout
160
+ binary = getattr(output, "buffer", None)
161
+ if binary is None:
162
+ output.write(patch)
163
+ output.flush()
164
+ return
165
+ cast(BinaryIO, binary).write(patch.encode("utf-8"))
166
+ cast(BinaryIO, binary).flush()
125
167
 
126
168
 
127
169
  def _doctor_report(mapper: CodebaseMapper) -> dict[str, object]:
@@ -136,3 +178,16 @@ def _doctor_report(mapper: CodebaseMapper) -> dict[str, object]:
136
178
  "problems": len(mapper.snapshot.problems),
137
179
  "errors": len(errors),
138
180
  }
181
+
182
+
183
+ def _print_guideline_report(report: GuidelineReport, output_format: str) -> None:
184
+ if output_format == "json":
185
+ print(json.dumps(report.to_mapping(), indent=2, sort_keys=True))
186
+ return
187
+ print(f"workspace: {report.workspace}")
188
+ print(f"profiles: {len(report.profiles)}")
189
+ print(f"findings: {len(report.findings)}")
190
+ for finding in report.findings:
191
+ line = finding.range.start_line + 1
192
+ character = finding.range.start_character + 1
193
+ print(f"{finding.range.path}:{line}:{character}: {finding.severity} {finding.code}: {finding.message}")