agent-codinglanguage-mapper 1.0.0__py3-none-any.whl

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 (42) hide show
  1. agent_codinglanguage_mapper/__init__.py +20 -0
  2. agent_codinglanguage_mapper/__main__.py +4 -0
  3. agent_codinglanguage_mapper/_version.py +2 -0
  4. agent_codinglanguage_mapper/adapters/__init__.py +4 -0
  5. agent_codinglanguage_mapper/adapters/delphi.py +822 -0
  6. agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py +6 -0
  7. agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py +29 -0
  8. agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py +345 -0
  9. agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py +460 -0
  10. agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py +2674 -0
  11. agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py +237 -0
  12. agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py +1832 -0
  13. agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py +371 -0
  14. agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py +193 -0
  15. agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py +997 -0
  16. agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py +518 -0
  17. agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py +319 -0
  18. agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py +375 -0
  19. agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py +1384 -0
  20. agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py +17 -0
  21. agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py +67 -0
  22. agent_codinglanguage_mapper/adapters/tree_sitter.py +1722 -0
  23. agent_codinglanguage_mapper/cli.py +138 -0
  24. agent_codinglanguage_mapper/discovery.py +1328 -0
  25. agent_codinglanguage_mapper/indexer.py +1102 -0
  26. agent_codinglanguage_mapper/integration.py +186 -0
  27. agent_codinglanguage_mapper/lsp_server.py +413 -0
  28. agent_codinglanguage_mapper/lsp_service.py +447 -0
  29. agent_codinglanguage_mapper/mapper.py +596 -0
  30. agent_codinglanguage_mapper/models.py +101 -0
  31. agent_codinglanguage_mapper/protocol.py +152 -0
  32. agent_codinglanguage_mapper/rendering.py +153 -0
  33. agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts +191 -0
  34. agent_codinglanguage_mapper/templates/skill/SKILL.md +52 -0
  35. agent_codinglanguage_mapper/worker.py +29 -0
  36. agent_codinglanguage_mapper/workspace.py +114 -0
  37. agent_codinglanguage_mapper-1.0.0.dist-info/METADATA +383 -0
  38. agent_codinglanguage_mapper-1.0.0.dist-info/RECORD +42 -0
  39. agent_codinglanguage_mapper-1.0.0.dist-info/WHEEL +5 -0
  40. agent_codinglanguage_mapper-1.0.0.dist-info/entry_points.txt +2 -0
  41. agent_codinglanguage_mapper-1.0.0.dist-info/licenses/LICENSE +373 -0
  42. agent_codinglanguage_mapper-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,114 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from dataclasses import dataclass, field, fields, is_dataclass
6
+ from types import MappingProxyType
7
+ from typing import Any, Callable, Mapping, TypeVar, cast
8
+
9
+ from .models import Language, Problem, Project, Reference, Relation, SourceFile, Symbol
10
+
11
+
12
+ def stable_id(kind: str, *parts: str) -> str:
13
+ material = "\x1f".join((kind, *parts)).encode("utf-8")
14
+ return f"{kind}:{hashlib.sha256(material).hexdigest()[:20]}"
15
+
16
+
17
+ def _record(value: object) -> object:
18
+ if hasattr(value, "value"):
19
+ return getattr(value, "value")
20
+ if isinstance(value, tuple):
21
+ return [_record(item) for item in value]
22
+ if isinstance(value, dict):
23
+ return {key: _record(item) for key, item in sorted(value.items())}
24
+ if is_dataclass(value) and not isinstance(value, type):
25
+ instance = cast(Any, value)
26
+ return {item.name: _record(getattr(instance, item.name)) for item in fields(instance)}
27
+ return value
28
+
29
+
30
+ _T = TypeVar("_T")
31
+
32
+
33
+ def _group(items: tuple[_T, ...], key: Callable[[_T], str]) -> dict[str, tuple[_T, ...]]:
34
+ grouped: dict[str, list[_T]] = {}
35
+ for item in items:
36
+ grouped.setdefault(key(item), []).append(item)
37
+ return {key: tuple(value) for key, value in grouped.items()}
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class WorkspaceSnapshot:
42
+ projects: tuple[Project, ...] = ()
43
+ files: tuple[SourceFile, ...] = ()
44
+ symbols: tuple[Symbol, ...] = ()
45
+ references: tuple[Reference, ...] = ()
46
+ relations: tuple[Relation, ...] = ()
47
+ problems: tuple[Problem, ...] = ()
48
+ source_digests: tuple[tuple[str, str], ...] = ()
49
+ metadata_digests: tuple[tuple[str, str], ...] = ()
50
+ revision: str = field(init=False)
51
+ projects_by_id: Mapping[str, Project] = field(init=False, repr=False)
52
+ files_by_id: Mapping[str, SourceFile] = field(init=False, repr=False)
53
+ symbols_by_id: Mapping[str, Symbol] = field(init=False, repr=False)
54
+ symbols_by_file: Mapping[str, tuple[Symbol, ...]] = field(init=False, repr=False)
55
+ symbol_aliases_by_id: Mapping[str, tuple[Symbol, ...]] = field(init=False, repr=False)
56
+ relations_by_source: Mapping[str, tuple[Relation, ...]] = field(init=False, repr=False)
57
+ relations_by_target: Mapping[str, tuple[Relation, ...]] = field(init=False, repr=False)
58
+
59
+ def __post_init__(self) -> None:
60
+ names = (
61
+ "projects",
62
+ "files",
63
+ "symbols",
64
+ "references",
65
+ "relations",
66
+ "problems",
67
+ "source_digests",
68
+ "metadata_digests",
69
+ )
70
+ for name in names:
71
+ object.__setattr__(self, name, tuple(getattr(self, name)))
72
+ revision_names = ("projects", "files", "source_digests", "metadata_digests")
73
+ payload = {name: _record(getattr(self, name)) for name in revision_names}
74
+ encoded = json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True).encode("utf-8")
75
+ object.__setattr__(self, "revision", hashlib.sha256(encoded).hexdigest())
76
+ object.__setattr__(self, "projects_by_id", MappingProxyType({item.project_id: item for item in self.projects}))
77
+ object.__setattr__(self, "files_by_id", MappingProxyType({item.file_id: item for item in self.files}))
78
+ object.__setattr__(self, "symbols_by_id", MappingProxyType({item.target_id: item for item in self.symbols}))
79
+ object.__setattr__(self, "symbols_by_file", MappingProxyType(_group(self.symbols, lambda item: item.file_id)))
80
+ alias_groups: dict[tuple[object, ...], list[Symbol]] = {}
81
+ for symbol in self.symbols:
82
+ alias_groups.setdefault(_symbol_alias_key(symbol), []).append(symbol)
83
+ aliases_by_id = {
84
+ symbol.target_id: tuple(group)
85
+ for group in alias_groups.values()
86
+ for symbol in group
87
+ }
88
+ object.__setattr__(self, "symbol_aliases_by_id", MappingProxyType(aliases_by_id))
89
+ object.__setattr__(
90
+ self,
91
+ "relations_by_source",
92
+ MappingProxyType(_group(self.relations, lambda item: item.source_id)),
93
+ )
94
+ object.__setattr__(
95
+ self,
96
+ "relations_by_target",
97
+ MappingProxyType(_group(self.relations, lambda item: item.target_id)),
98
+ )
99
+
100
+
101
+ def _symbol_alias_key(symbol: Symbol) -> tuple[object, ...]:
102
+ if symbol.language is not Language.DELPHI:
103
+ return (symbol.target_id,)
104
+ anchor = symbol.name_range or symbol.range
105
+ return (
106
+ symbol.project_id,
107
+ symbol.language,
108
+ symbol.kind,
109
+ symbol.role,
110
+ symbol.name.casefold(),
111
+ symbol.qualified_name.casefold(),
112
+ " ".join(symbol.signature.casefold().split()),
113
+ anchor,
114
+ )
@@ -0,0 +1,383 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-codinglanguage-mapper
3
+ Version: 1.0.0
4
+ Summary: Agent-focused semantic mapping and language services for mixed-language codebases.
5
+ Author: Dark Light
6
+ License-Expression: MPL-2.0
7
+ Classifier: Development Status :: 5 - Production/Stable
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Operating System :: MacOS
11
+ Classifier: Operating System :: Microsoft :: Windows
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Compilers
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: <3.15,>=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: lark<2,>=1.1.9
25
+ Requires-Dist: lsprotocol>=2023.0.1
26
+ Requires-Dist: pathspec<1,>=0.12
27
+ Requires-Dist: pygls<2,>=1.3.0
28
+ Requires-Dist: tomli>=2; python_version < "3.11"
29
+ Requires-Dist: tree-sitter==0.26.0
30
+ Requires-Dist: tree-sitter-python==0.25.0
31
+ Requires-Dist: tree-sitter-rust==0.24.2
32
+ Requires-Dist: tree-sitter-c-sharp==0.23.5
33
+ Requires-Dist: tree-sitter-cpp==0.23.4
34
+ Provides-Extra: test
35
+ Requires-Dist: pytest>=8; extra == "test"
36
+ Requires-Dist: pytest-cov>=5; extra == "test"
37
+ Requires-Dist: tomli>=2; python_version < "3.11" and extra == "test"
38
+ Provides-Extra: dev
39
+ Requires-Dist: build>=1.2; extra == "dev"
40
+ Requires-Dist: mypy==1.19.1; extra == "dev"
41
+ Requires-Dist: pytest>=8; extra == "dev"
42
+ Requires-Dist: pytest-cov>=5; extra == "dev"
43
+ Requires-Dist: ruff>=0.6; extra == "dev"
44
+ Requires-Dist: tomli>=2; extra == "dev"
45
+ Requires-Dist: twine>=5; extra == "dev"
46
+ Dynamic: license-file
47
+
48
+ # Agent Coding Language Mapper
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.
51
+
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
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ python -m pip install agent-codinglanguage-mapper
58
+ ```
59
+
60
+ Python 3.10 through 3.14 is supported on Windows, macOS, and Linux.
61
+
62
+ Check the installation against a repository:
63
+
64
+ ```bash
65
+ codinglanguage-mapper doctor --root .
66
+ codinglanguage-mapper view --root . --layer overview --format markdown
67
+ ```
68
+
69
+ ## Python API
70
+
71
+ ```python
72
+ from agent_codinglanguage_mapper import AgentRequest, CodebaseMapper, Language
73
+
74
+ with CodebaseMapper.open(".", languages="auto") as mapper:
75
+ found = mapper.request(
76
+ AgentRequest(
77
+ action="find",
78
+ query="PaymentService",
79
+ languages=(Language.PYTHON, Language.CSHARP),
80
+ )
81
+ )
82
+
83
+ item = found.result["items"][0]
84
+ detail = mapper.request(
85
+ AgentRequest(
86
+ action="inspect",
87
+ target_id=item["target_id"],
88
+ detail="body",
89
+ )
90
+ )
91
+ print(detail.to_mapping())
92
+ ```
93
+
94
+ The public types are:
95
+
96
+ - `CodebaseMapper`
97
+ - `AgentRequest` and `AgentResponse`
98
+ - `Language`
99
+ - `Project` and `SourceFile`
100
+ - `Symbol`, `Reference`, and `Relation`
101
+ - `Problem` and `SourceRange`
102
+
103
+ 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
+
105
+ `CodebaseMapper.open()` creates an outline index first. `inspect`, `focus`, and outgoing `callees`/`uses` traces load detail only for the selected source file. Incoming `references`/`callers`/`used_by` traces load the remaining workspace detail because their evidence can originate in any indexed file. Parsed detail and focus remain resident for the mapper session. The same optimized path is used for small and large files.
106
+
107
+ The private session index retains each parser-native outline tree, its source buffer, a source digest, and a lightweight file fingerprint. A detail upgrade therefore queries the existing tree instead of rereading or reparsing every indexed source. When an indexed source changes during a worker session, the mapper rebuilds the outline snapshot, updates `workspace_revision`, clears stale detail/focus state, and invalidates old cursors before answering the next request. Parser-native nodes never appear in the public result types.
108
+
109
+ ## CLI
110
+
111
+ The installed command is `codinglanguage-mapper`.
112
+
113
+ ```bash
114
+ # Layered views
115
+ codinglanguage-mapper view --root . --layer projects --format markdown
116
+ codinglanguage-mapper view --root . --layer files --language rust --format json
117
+ codinglanguage-mapper view --root . --layer symbols --query PaymentService
118
+ codinglanguage-mapper view --root . --layer implementation --query PaymentService
119
+ codinglanguage-mapper view --root . --layer references --query PaymentService
120
+
121
+ # Persistent JSON index
122
+ codinglanguage-mapper index --root . --out .mapper/index.json
123
+
124
+ # Discovery and parser diagnostics
125
+ codinglanguage-mapper doctor --root . --format json
126
+
127
+ # Language Server Protocol over stdio
128
+ codinglanguage-mapper lsp --root .
129
+
130
+ # Protocol 3 NDJSON worker
131
+ codinglanguage-mapper worker --root .
132
+ ```
133
+
134
+ Available view layers are `overview`, `projects`, `languages`, `files`, `file`, `symbols`, `symbol`, `implementation`, `references`, and `problems`.
135
+
136
+ ## Protocol 3
137
+
138
+ Protocol 3 is the bounded request/response contract used by the worker and OpenCode plugin.
139
+
140
+ Actions:
141
+
142
+ | Action | Purpose |
143
+ | --- | --- |
144
+ | `open` | Return projects and establish the workspace revision. |
145
+ | `find` | Search indexed symbols with optional project, file, and language filters. |
146
+ | `inspect` | Return one selected detail layer for a target. |
147
+ | `trace` | Follow one explicit relation from a target. |
148
+ | `focus` | Select a target while preserving project/file/language focus. |
149
+ | `problems` | Return structured discovery, syntax, and semantic problems. |
150
+
151
+ Details are `summary`, `declaration`, `members`, `context`, `body`, and `implementations`. Relations are `references`, `callers`, `callees`, `uses`, `used_by`, `inherits`, `implements`, and `ffi`.
152
+
153
+ ```json
154
+ {
155
+ "action": "trace",
156
+ "target_id": "symbol:...",
157
+ "relation": "callers",
158
+ "languages": ["csharp", "cpp"],
159
+ "max_items": 12,
160
+ "max_chars": 12000
161
+ }
162
+ ```
163
+
164
+ Each response contains:
165
+
166
+ - `schema`: always `3`
167
+ - `workspace_revision`: invalidates stale cursors after codebase changes
168
+ - `focus`: current project, file, target, and language selection
169
+ - `result`: bounded result items
170
+ - `page`: returned/total counts, truncation state, and `next_cursor`
171
+ - `context`: character count and approximate token count
172
+
173
+ Symbol items include a one-based `citation` and a `role` value. `role` is `declaration`, `implementation`, or `definition`; clients must use it when the language distinguishes a declaration from its implementation and must copy `citation` verbatim instead of recalculating it from the zero-based ranges.
174
+
175
+ Relation items include `target_name` and, for statically identifiable native imports, `target_library`. Parser-native nodes and recovery artifacts are never exposed through Protocol 3.
176
+
177
+ After `focus`, an unfiltered `find` inherits the focused project, file, and languages. An explicit `file_id` replaces the focused file. An explicit project or language filter starts a broader scope and clears incompatible narrower inherited filters; include `file_id` explicitly when that narrower restriction is still intended.
178
+
179
+ Defaults are 12 items and 12,000 characters. `max_chars` is capped at 40,000. Source bodies are chunked at 6,000 characters. When `page.truncated` is true, continue with the non-empty `next_cursor`; do not infer omitted items. An individual bounded summary can also contain `"truncated": true` while still exposing its `target_id`, name, language, and citation so the target can be inspected directly.
180
+
181
+ ## Resolution Semantics
182
+
183
+ The mapper never fabricates a relation to make a graph look complete.
184
+
185
+ | Resolution | Meaning |
186
+ | --- | --- |
187
+ | `complete` | The relation is proven inside the indexed workspace. |
188
+ | `sound_partial` | Returned evidence is valid, but the available static information may be incomplete. |
189
+ | `ambiguous` | More than one valid target remains. |
190
+ | `unresolved` | No defensible target can be selected. |
191
+
192
+ Same-language cross-file targets become `complete` only when the target is visible in the same project through an explicit Python/Rust import, C/C++ include, Delphi `uses` clause, or the applicable C# namespace rules. A same-name symbol elsewhere in the workspace is not sufficient.
193
+
194
+ Cross-language FFI is recognized only from explicit declarations: Rust `extern`, C/C++ ABI exports, C# `DllImport`/`LibraryImport`, Delphi `external`/`exports`, and statically identifiable Python `ctypes`/`cffi` usage. An import becomes `complete` only when its literal library identity also matches the exporter identity after conventional `lib` prefix and `.dll`/`.dylib`/`.so` suffix normalization. C/C++ exporter identity comes from explicit loadable CMake targets such as `add_library(metrics SHARED metrics.cpp)` or `MODULE` libraries; static libraries, executables, and unspecified library kinds are not treated as runtime FFI outputs. Delphi exporter identity comes from the `library metrics;` declaration. A source filename is never treated as proof of a native output name, and custom or unresolved outputs remain `sound_partial` or `unresolved`.
195
+
196
+ A resolved `ffi` trace includes complete `source_symbol` and `target_symbol` mappings. Their `language`, `role`, and `citation` fields provide both endpoints without a second name-based search.
197
+
198
+ ## Project Discovery
199
+
200
+ No environment variable is required for normal discovery. The workspace scanner respects `.gitignore` files at every directory level, applies each pattern relative to its directory, skips standard build/cache directories, and enforces the repository boundary. Directory symlinks are not followed, and workspace-escaping source roots are reported instead of indexed.
201
+
202
+ Supported metadata includes:
203
+
204
+ - Python `pyproject.toml`, `setup.cfg`, and conventional/source layouts
205
+ - Cargo packages and workspaces
206
+ - `.sln` and `.csproj`
207
+ - Delphi `.dpr`, `.dpk`, `.dproj`, and `.groupproj`, including unit search paths, include paths, source paths, project defines, and source declarations; `.dpr` and `.dpk` files are also indexed as source
208
+ - C/C++ `compile_commands.json`, `CMakeLists.txt`, and `.vcxproj`
209
+
210
+ Build scripts are parsed as data and are never executed. Cargo custom library and binary paths are combined rather than treated as alternatives, and solution files resolve their referenced C# project membership. Multiple named project files in one directory keep distinct project identities; matching `.dpr`/`.dproj` pairs share one Delphi project identity. Explicit source membership has priority over broad solution or group metadata. If multiple implicit projects remain equally valid owners, the file is assigned to the synthetic workspace project and an `ambiguous-project-ownership` problem lists the candidate project files. Unresolved variables, missing generated files, missing project references, missing include roots, and paths outside the workspace become structured `Problem` records.
211
+
212
+ ## Language Coverage
213
+
214
+ Release-blocking fixtures and LSP assertions cover:
215
+
216
+ | Language | Supported stable range |
217
+ | --- | --- |
218
+ | Python | 2.7 and 3.0 through 3.14 |
219
+ | Rust | Editions 2015, 2018, 2021, and 2024 |
220
+ | C# | C# 1 through C# 14 |
221
+ | Delphi | Delphi 7 through Delphi 13 Florence |
222
+ | C++ | C++98/03 through C++23 |
223
+
224
+ Stable GNU/MSVC C++ extensions and Delphi compiler directives have dedicated fixtures. Preview, Nightly, compiler-internal, and draft syntax is Best-Effort and is reported through explicit compatibility handlers. Unknown stable syntax remains a release-blocking `syntax-error`; parser recovery is never silently accepted.
225
+
226
+ Run the offline formal audit:
227
+
228
+ ```bash
229
+ python scripts/audit_language_matrix.py
230
+ pytest -q tests/test_language_matrix.py
231
+ ```
232
+
233
+ Pinned external evaluations cover CPython, Rust, Roslyn, LLVM, DUnitX, and the official corpora for each pinned Tree-sitter grammar. Populate a missing corpus cache only as an explicit evaluation operation:
234
+
235
+ ```bash
236
+ python scripts/evaluate_external_corpora.py --fetch --max-files 20
237
+ ```
238
+
239
+ Every subsequent run is offline and rejects a dirty or revision-mismatched cache:
240
+
241
+ ```bash
242
+ python scripts/evaluate_external_corpora.py \
243
+ --output benchmarks/results/external-corpora.json
244
+ ```
245
+
246
+ Corpora are evaluation inputs only. They are not vendored and are never accessed at package runtime.
247
+
248
+ ## LSP Configuration
249
+
250
+ Start the server with:
251
+
252
+ ```bash
253
+ codinglanguage-mapper lsp --root /absolute/path/to/workspace
254
+ ```
255
+
256
+ An editor client should launch that command over stdio with the workspace directory as its root. The server advertises diagnostics, definition, hover, references, safe rename, document symbols, workspace symbols, and completion for all five languages.
257
+
258
+ Safe rename requires an exact declaration range and refuses unresolved or ambiguous references. Diagnostics retain the mapper's structured severity and source ranges.
259
+
260
+ Example generic client configuration:
261
+
262
+ ```json
263
+ {
264
+ "command": "codinglanguage-mapper",
265
+ "args": ["lsp", "--root", "/absolute/path/to/workspace"],
266
+ "transport": "stdio",
267
+ "filetypes": ["python", "rust", "cs", "pascal", "cpp"]
268
+ }
269
+ ```
270
+
271
+ ## OpenCode Integration
272
+
273
+ Install the packaged skill, plugin, and restricted agent configuration into a repository:
274
+
275
+ ```bash
276
+ codinglanguage-mapper opencode install --target . --write
277
+ ```
278
+
279
+ This creates:
280
+
281
+ ```text
282
+ .agents/skills/mixed-codebase-navigator/SKILL.md
283
+ .opencode/plugins/codebase_map.ts
284
+ opencode.json
285
+ ```
286
+
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.
288
+
289
+ Run it with:
290
+
291
+ ```bash
292
+ opencode run \
293
+ --agent mixed-codebase-navigator \
294
+ "Find PaymentService, inspect its implementation, and cite the callers. Use only the installed skill and codebase_map."
295
+ ```
296
+
297
+ A typical investigation should:
298
+
299
+ 1. Call `codebase_map` with `action: open`.
300
+ 2. Use `find` with the narrowest useful language/project/file filters.
301
+ 3. Select a returned `target_id` with `focus`.
302
+ 4. Request only the required `inspect` detail.
303
+ 5. Use `trace` only for explicit Protocol 3 relations.
304
+ 6. Follow `next_cursor` when evidence is truncated.
305
+
306
+ ## Large-Workspace Performance
307
+
308
+ 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:
309
+
310
+ - cold parse P95 per 100k file: 3 seconds
311
+ - mixed overview P95: 5 seconds
312
+ - warm search P95: 1.5 seconds
313
+ - inspect and focus P95: 0.5 seconds each
314
+
315
+ Reproduce the benchmark:
316
+
317
+ ```bash
318
+ python scripts/benchmark_large_workspaces.py \
319
+ --lines 100000 \
320
+ --samples 5 \
321
+ --output benchmarks/results/macos-current.json
322
+ ```
323
+
324
+ The command exits nonzero when any budget is exceeded.
325
+ Private Linux CI records and uploads the same measurements with `--report-only`; the Apple Silicon release budgets are enforced only on the documented reference Mac and are not applied to unrelated hosted hardware.
326
+
327
+ ## Offline Ornith/OpenCode Evaluation
328
+
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.
330
+
331
+ Inspect the plan without launching a model:
332
+
333
+ ```bash
334
+ python scripts/run_opencode_e2e.py --plan
335
+ ```
336
+
337
+ Verify the exact local executables, versions, model revision, and weight shards:
338
+
339
+ ```bash
340
+ python scripts/run_opencode_e2e.py --verify-runtime
341
+ ```
342
+
343
+ Run all six scenarios and retain complete evidence:
344
+
345
+ ```bash
346
+ HF_HUB_OFFLINE=1 \
347
+ TRANSFORMERS_OFFLINE=1 \
348
+ HF_DATASETS_OFFLINE=1 \
349
+ PIP_NO_INDEX=1 \
350
+ UV_OFFLINE=1 \
351
+ OPENCODE_DISABLE_AUTOUPDATE=1 \
352
+ python scripts/run_opencode_e2e.py \
353
+ --artifacts artifacts/opencode-ornith-vllm
354
+ ```
355
+
356
+ The harness stores server logs, isolated OpenCode stdout/stderr, exported sessions, extracted tool calls, runtime metadata, and per-scenario assertions below the selected artifact directory. It probes `/v1/chat/completions`; a successful `/v1/models` response alone is not accepted as server readiness.
357
+
358
+ For a diagnostic run of one scenario, keep the same release checks and add a selector:
359
+
360
+ ```bash
361
+ python scripts/run_opencode_e2e.py \
362
+ --scenario python \
363
+ --artifacts artifacts/opencode-ornith-python
364
+ ```
365
+
366
+ The pinned Metal runtime uses `VLLM_METAL_MEMORY_FRACTION=0.90`. Before launch, the harness waits for at least 20.5 GB of available unified memory. The 24,576-token context keeps enough room for OpenCode's system prompt, mapped source evidence, tool-calling rounds, and up to 4,096 output tokens on the 32 GB reference Mac. OpenCode receives this context limit directly from the same runtime lock as vLLM, so client and server limits cannot drift. The harness supplies an explicit session title so OpenCode does not spend the single local inference slot generating one, and it runs the restricted agent deterministically with a bounded iteration count. The server log must show a KV-cache capacity above 24,576 tokens.
367
+
368
+ ## Development and Release Gates
369
+
370
+ ```bash
371
+ python -m pytest -q
372
+ ruff check src tests scripts
373
+ mypy src scripts
374
+ python scripts/audit_language_matrix.py
375
+ python -m build
376
+ python -m twine check dist/*
377
+ ```
378
+
379
+ Release artifacts must be tested from a fresh virtual environment. The wheel must contain the skill/plugin templates and must not contain, depend on, or import `python-delphi-lsp`.
380
+
381
+ ## License
382
+
383
+ Copyright is attributed to `Dark Light`. The package is licensed under MPL-2.0. Ported Delphi frontend files remain under the same license; `python-delphi-lsp` is not installed, imported, bundled as a subpackage, or modified by this project.
@@ -0,0 +1,42 @@
1
+ agent_codinglanguage_mapper/__init__.py,sha256=obrrVAfq6Y_Qh5UHZ8YuJWV6BDdiofqAvoVWr5RHru0,448
2
+ agent_codinglanguage_mapper/__main__.py,sha256=D31U8_ux95qF64EQ8ReT25nabzxh7ped5avpobXz_bM,49
3
+ agent_codinglanguage_mapper/_version.py,sha256=uyfGiipFnhOCQlqywx7wsgp6d-SYnqPqsPQd_xePZl8,23
4
+ agent_codinglanguage_mapper/cli.py,sha256=2y-Ued0B57inojA_xOAThaBLJ_q1xTqo8bC2wAOosRE,5422
5
+ agent_codinglanguage_mapper/discovery.py,sha256=rzZ3iSOrFZ3eXXCRFTw0rN2yxoW9Z1SSxIZrhPlf1Y8,50756
6
+ agent_codinglanguage_mapper/indexer.py,sha256=-s_3Yyq_D26ljOcDMAlJ-QyG05w79qfHnYk5spzuL7c,39260
7
+ agent_codinglanguage_mapper/integration.py,sha256=0lFo4oXOtkrOy9iJS1OCvSO0hBhrYDDPUUlJJSzcgrE,6976
8
+ agent_codinglanguage_mapper/lsp_server.py,sha256=LtXalnGP9mmwdCHudCHE80lkR-CO-zcg575dGbX-xgA,15123
9
+ agent_codinglanguage_mapper/lsp_service.py,sha256=M-ACQT45Yii57ObbJAVYttgtS3NhZw35kaIIxREPvC8,19031
10
+ agent_codinglanguage_mapper/mapper.py,sha256=iBhau3-jehmNawoeN-TAaYXMc6_sEovraoSuMSSbINM,25474
11
+ agent_codinglanguage_mapper/models.py,sha256=YCMp0tmOyCqyaAH7XKgUdGAfr9wskdbJYMrtT3Pafd8,2083
12
+ agent_codinglanguage_mapper/protocol.py,sha256=SXAJUzdi2b8L1amQgmT9Fd3SpeZ-Hr-jSvA5uZlCLqs,6421
13
+ agent_codinglanguage_mapper/rendering.py,sha256=rqmlpHp3vxwoh-tES1X7VBy3vr30atGyHQ6egz80rEY,6054
14
+ agent_codinglanguage_mapper/worker.py,sha256=6wcIDJ2SNUASDD5DJngm5SrOurOw52GWj52AhGchC8Q,1140
15
+ agent_codinglanguage_mapper/workspace.py,sha256=5vPgt7h9YQcKgVkVDq7m8dUzGuuN4y5UL9aPhhOLozA,4724
16
+ agent_codinglanguage_mapper/adapters/__init__.py,sha256=qLG_Oz2EtTDGXjkyCFaFJjfifbyeF0HOBDJMQV9HB5U,401
17
+ agent_codinglanguage_mapper/adapters/delphi.py,sha256=9POkTqsS0DqkAQGR1LWZVuS5zQ4dRG4AdQKoWFAjaY0,33645
18
+ agent_codinglanguage_mapper/adapters/tree_sitter.py,sha256=A3l5kVWzyNu362Zft-fqvKOv4EomUs7YlQKDQ2CuN3E,71786
19
+ agent_codinglanguage_mapper/adapters/delphi_frontend/__init__.py,sha256=Y7__997bmRQ7BKZoM0qLbp6S6s5W5m8se7ILL7Vw0Js,199
20
+ agent_codinglanguage_mapper/adapters/delphi_frontend/comment_builder.py,sha256=XvFW7WTbYy7yGN3MG40gtabTvhGj1ea1MYkySDbVMDA,832
21
+ agent_codinglanguage_mapper/adapters/delphi_frontend/consts.py,sha256=qM40iwxXmvEileWHJVLMYlQSkLoLyQaqM-Zscz3VJbs,5958
22
+ agent_codinglanguage_mapper/adapters/delphi_frontend/grammar.py,sha256=QWEMSUKr0e1xlJOveZtp7K-MvhlkvDgxkD0iUKIyxKU,18577
23
+ agent_codinglanguage_mapper/adapters/delphi_frontend/lark_builder.py,sha256=KTXxr5WrLMvzdb0F71JMzFqExLiEPF1_cwGrZkurgqQ,118651
24
+ agent_codinglanguage_mapper/adapters/delphi_frontend/lark_tokens.py,sha256=xT_GES2z6p1IdN3EnoKE9RcUM6suu1RV3J-0FEJN2r8,4176
25
+ agent_codinglanguage_mapper/adapters/delphi_frontend/lsp_server.py,sha256=fznUAhcvwTgdiiDrv1nEqW_UsiOJ6Lldd_x-ooGSCLk,65940
26
+ agent_codinglanguage_mapper/adapters/delphi_frontend/nodes.py,sha256=LW8KUgNCg9MHK_2NmzrgCMMJNcBwa4C76XwKoS7kt4E,13556
27
+ agent_codinglanguage_mapper/adapters/delphi_frontend/parser.py,sha256=-NGETYDomzko-OpQtCLEGUfGpxQKVKeLp23_FY1DL1M,6559
28
+ agent_codinglanguage_mapper/adapters/delphi_frontend/preprocessor.py,sha256=7cEfbN7zhWezAiroZ5t-S3H22v4aNTcimQRAigWMvtw,36727
29
+ agent_codinglanguage_mapper/adapters/delphi_frontend/project_discovery.py,sha256=ei7Iy19EMpTWjOFpKPc9hDG2oH1MUGxKwCLnibJp_TM,17336
30
+ agent_codinglanguage_mapper/adapters/delphi_frontend/project_indexer.py,sha256=R5oD4sYsIi2nAlOCr-Mq3-CFkINeC19t0vtKkciCRmg,11227
31
+ agent_codinglanguage_mapper/adapters/delphi_frontend/semantic.py,sha256=FZ9x_QsIS_u-1DlzVlYgRqH9gQZ5ySnDAD-xHwzblU8,9808
32
+ agent_codinglanguage_mapper/adapters/delphi_frontend/semantic_builder.py,sha256=ulA7xHJpltjc6cTo5wh9yTcYazuIykM-YLMXD1h-wzk,58680
33
+ agent_codinglanguage_mapper/adapters/delphi_frontend/source_reader.py,sha256=HWiw25sLVZ6s1GGpMl17uZ-o68HoxTEd3Z0__m1vsSE,520
34
+ agent_codinglanguage_mapper/adapters/delphi_frontend/workspace.py,sha256=TU__SujItRlW8hB2kuYC7ZJx1WQVOj7frYxvo7rDqeI,2137
35
+ agent_codinglanguage_mapper/templates/opencode/plugins/codebase_map.ts,sha256=RdXvLtL9ieyrhkxv3khbrEjXBeroVyZVSAG4dAzKYk4,6838
36
+ agent_codinglanguage_mapper/templates/skill/SKILL.md,sha256=pyKVldpHWezuiswG5FKI3Rxpmjc9fEYwAHJ3-W4WjTs,3227
37
+ agent_codinglanguage_mapper-1.0.0.dist-info/licenses/LICENSE,sha256=-rPda9qyJvHAhjCx3ZF-Efy07F4eAg4sFvg6ChOGPoU,16726
38
+ agent_codinglanguage_mapper-1.0.0.dist-info/METADATA,sha256=gI1ywuU2NvjKRVJCN7bw8AeAbYuQxRsVQIRP2v8Ias0,19102
39
+ agent_codinglanguage_mapper-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
40
+ agent_codinglanguage_mapper-1.0.0.dist-info/entry_points.txt,sha256=WaoNMRnakxcGmddrFFn74vcpa66YDQHMgDpXF2lbKsI,79
41
+ agent_codinglanguage_mapper-1.0.0.dist-info/top_level.txt,sha256=EYFF-VOTZBm6V7KzaUxkbs0qVTF3w_WT2bsLc6B3Ry0,28
42
+ agent_codinglanguage_mapper-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ codinglanguage-mapper = agent_codinglanguage_mapper.cli:main