python-delphi-lsp 1.1.1__tar.gz → 2.0.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.
- python_delphi_lsp-2.0.1/PKG-INFO +380 -0
- python_delphi_lsp-2.0.1/README.md +341 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/__init__.py +22 -0
- python_delphi_lsp-2.0.1/delphi_lsp/_version.py +1 -0
- python_delphi_lsp-2.0.1/delphi_lsp/agent_cli.py +243 -0
- python_delphi_lsp-2.0.1/delphi_lsp/agent_context.py +2138 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/agent_layers.py +67 -2
- python_delphi_lsp-2.0.1/delphi_lsp/agent_metrics.py +82 -0
- python_delphi_lsp-2.0.1/delphi_lsp/agent_protocol.py +391 -0
- python_delphi_lsp-2.0.1/delphi_lsp/agent_relations.py +859 -0
- python_delphi_lsp-2.0.1/delphi_lsp/agent_templates.py +580 -0
- python_delphi_lsp-2.0.1/delphi_lsp/agent_workspace.py +695 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/lark_builder.py +14 -2
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/lsp_server.py +270 -48
- python_delphi_lsp-2.0.1/delphi_lsp/metrics.py +759 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/project_discovery.py +183 -40
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/project_indexer.py +6 -0
- python_delphi_lsp-2.0.1/delphi_lsp/source_reader.py +17 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/workspace.py +15 -1
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/opencode.json +1 -6
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/pyproject.toml +5 -5
- python_delphi_lsp-2.0.1/python_delphi_lsp.egg-info/PKG-INFO +380 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/python_delphi_lsp.egg-info/SOURCES.txt +35 -21
- python_delphi_lsp-2.0.1/python_delphi_lsp.egg-info/entry_points.txt +3 -0
- python_delphi_lsp-2.0.1/python_delphi_lsp.egg-info/top_level.txt +1 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/audit_delphi_language_features.py +3 -3
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_codebase_skill_test.py +227 -18
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_opencode_test.py +1 -1
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/generate_release_evidence.py +67 -19
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/run_opencode_lsp_probe.py +133 -37
- python_delphi_lsp-2.0.1/tests/test_agent_codebase.py +958 -0
- python_delphi_lsp-2.0.1/tests/test_agent_context.py +1773 -0
- python_delphi_lsp-2.0.1/tests/test_agent_metrics.py +149 -0
- python_delphi_lsp-2.0.1/tests/test_agent_protocol.py +676 -0
- python_delphi_lsp-2.0.1/tests/test_agent_relations.py +1197 -0
- python_delphi_lsp-2.0.1/tests/test_agent_worker.py +448 -0
- python_delphi_lsp-2.0.1/tests/test_agent_workspace.py +1280 -0
- python_delphi_lsp-2.0.1/tests/test_bootstrap_vllm_codebase_skill.py +209 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_bootstrap_vllm_opencode.py +54 -9
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_diagnostics.py +1 -1
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_legacy_snippets.py +1 -1
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_lsp_features.py +3 -3
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_lsp_support.py +483 -18
- python_delphi_lsp-2.0.1/tests/test_metrics.py +188 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_opencode_probe.py +253 -0
- python_delphi_lsp-2.0.1/tests/test_package_metadata.py +137 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_parser.py +52 -2
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_preprocessor.py +2 -2
- python_delphi_lsp-2.0.1/tests/test_project_discovery.py +427 -0
- python_delphi_lsp-2.0.1/tests/test_project_indexer.py +398 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_release_evidence.py +33 -3
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_semantic.py +2 -2
- python_delphi_lsp-2.0.1/tests/test_workspace.py +85 -0
- python_delphi_lsp-1.1.1/PKG-INFO +0 -434
- python_delphi_lsp-1.1.1/README.md +0 -395
- python_delphi_lsp-1.1.1/delphiast/agent_cli.py +0 -113
- python_delphi_lsp-1.1.1/delphiast/agent_templates.py +0 -180
- python_delphi_lsp-1.1.1/delphiast/source_reader.py +0 -15
- python_delphi_lsp-1.1.1/python_delphi_lsp.egg-info/PKG-INFO +0 -434
- python_delphi_lsp-1.1.1/python_delphi_lsp.egg-info/entry_points.txt +0 -3
- python_delphi_lsp-1.1.1/python_delphi_lsp.egg-info/top_level.txt +0 -1
- python_delphi_lsp-1.1.1/tests/test_agent_codebase.py +0 -217
- python_delphi_lsp-1.1.1/tests/test_bootstrap_vllm_codebase_skill.py +0 -68
- python_delphi_lsp-1.1.1/tests/test_package_metadata.py +0 -57
- python_delphi_lsp-1.1.1/tests/test_project_discovery.py +0 -174
- python_delphi_lsp-1.1.1/tests/test_project_indexer.py +0 -152
- python_delphi_lsp-1.1.1/tests/test_workspace.py +0 -31
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/LICENSE +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/MANIFEST.in +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/binary.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/comment_builder.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/consts.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/grammar.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/lark_tokens.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/nodes.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/parser.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/preprocessor.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/semantic.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/semantic_builder.py +0 -0
- {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/writer.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/python_delphi_lsp.egg-info/requires.txt +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/check_ornith_cache.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/prepare_ornith_cache.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/start_ornith_vllm.sh +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/summarize_opencode_request_payloads.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/setup.cfg +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/constset.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/properties.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/library_demo.dpr +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/package_demo.dpk +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/program_demo.dpr +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_advanced.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_attributes.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_basic.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_consumer.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_generics.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_inheritance.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_math.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_properties.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_sections.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_statements.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_types.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_unresolved.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_with.pas +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_language_feature_matrix.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_opencode_config.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_opencode_request_payloads.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_ornith_cache_prepare.py +0 -0
- {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_vllm_start_script.py +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-delphi-lsp
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Python Delphi/Object Pascal parser, semantic indexer, and language server.
|
|
5
|
+
Author: Dark Light
|
|
6
|
+
License-Expression: MPL-2.0
|
|
7
|
+
Keywords: delphi,object-pascal,pascal,lsp,language-server,parser
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Operating System :: MacOS
|
|
12
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
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.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: lark>=1.1.9
|
|
25
|
+
Requires-Dist: pygls<2.0,>=1.3.0
|
|
26
|
+
Requires-Dist: lsprotocol>=2023.0.1
|
|
27
|
+
Provides-Extra: lsp
|
|
28
|
+
Requires-Dist: pygls<2.0,>=1.3.0; extra == "lsp"
|
|
29
|
+
Requires-Dist: lsprotocol>=2023.0.1; extra == "lsp"
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
32
|
+
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
34
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pygls<2.0,>=1.3.0; extra == "dev"
|
|
36
|
+
Requires-Dist: lsprotocol>=2023.0.1; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
# Python Delphi LSP
|
|
41
|
+
|
|
42
|
+
`python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
|
|
43
|
+
indexes, serves LSP, and provides bounded codebase navigation for agents.
|
|
44
|
+
Version 2.0.1 is authored by Dark Light and supports Windows, macOS, and Linux.
|
|
45
|
+
|
|
46
|
+
## Install and quick start
|
|
47
|
+
|
|
48
|
+
Install into the Python environment that will run the command:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python -m pip install python-delphi-lsp
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
On Windows, use `py -m pip install python-delphi-lsp` if that is your system
|
|
55
|
+
convention. On macOS and Linux, use `python3 -m pip install python-delphi-lsp`
|
|
56
|
+
when `python` is unavailable. Normal installed use needs neither a checkout
|
|
57
|
+
nor `PYTHONPATH`.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from delphi_lsp import parse
|
|
61
|
+
|
|
62
|
+
result = parse("unit Unit1; interface implementation end.", "Unit1.pas")
|
|
63
|
+
print(result.root)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
For semantic work across units, `build_workspace_semantics` returns per-file
|
|
67
|
+
models and a shared symbol index. `ProjectIndexer` follows a project entry
|
|
68
|
+
with explicit search paths, include paths, and defines.
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from delphi_lsp import ProjectIndexer, build_workspace_semantics
|
|
72
|
+
|
|
73
|
+
workspace = build_workspace_semantics({
|
|
74
|
+
"Unit1.pas": "unit Unit1; interface uses Unit2; implementation end.",
|
|
75
|
+
"Unit2.pas": "unit Unit2; interface implementation end.",
|
|
76
|
+
})
|
|
77
|
+
print(workspace.index.lookup("Unit2"))
|
|
78
|
+
|
|
79
|
+
project = ProjectIndexer(
|
|
80
|
+
search_paths=["src"], include_paths=["include"], defines=["DEBUG"]
|
|
81
|
+
).index("Main.dpr")
|
|
82
|
+
print(project.parsed_units)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Architecture metrics
|
|
86
|
+
|
|
87
|
+
The public metrics API analyzes a single unit or aggregates a complete project:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from delphi_lsp import analyze_project, analyze_unit
|
|
91
|
+
|
|
92
|
+
unit = analyze_unit(
|
|
93
|
+
"unit Alpha; interface implementation procedure Run; begin end; end.",
|
|
94
|
+
"Alpha.pas",
|
|
95
|
+
)
|
|
96
|
+
print(unit.lines.total_lines, unit.cyclomatic.maximum)
|
|
97
|
+
|
|
98
|
+
project = analyze_project({
|
|
99
|
+
"Main.dpr": "program Main; uses Alpha; begin end.",
|
|
100
|
+
"Alpha.pas": "unit Alpha; interface implementation end.",
|
|
101
|
+
})
|
|
102
|
+
print(project.total_loc)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Line results distinguish total, source, blank, comment-only, mixed-comment, and
|
|
106
|
+
compiler-directive lines. Project `total_loc` counts each `.dpr`, `.dpk`, and
|
|
107
|
+
`.pas` source once; `include_loc` counts unique `.inc` inputs separately, and
|
|
108
|
+
`total_loc_with_includes` combines both totals.
|
|
109
|
+
|
|
110
|
+
Cyclomatic complexity is reported per routine and as unit/project aggregates.
|
|
111
|
+
The result also includes complete Halstead counts and derived values, a
|
|
112
|
+
normalized 0–100 maintainability index, symbol counts, dependency edges,
|
|
113
|
+
afferent coupling (fan-in), efferent coupling (fan-out), instability,
|
|
114
|
+
abstractness, and distance from the main sequence. Coupling detail separates
|
|
115
|
+
internal from external dependencies. Empty or partial inputs produce finite
|
|
116
|
+
JSON values; unreadable agent-workspace inputs are reported as metric problems.
|
|
117
|
+
|
|
118
|
+
Run the stdio language server with `delphi-lsp`, or equivalently:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python -m delphi_lsp.lsp_server
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## OpenCode LSP configuration
|
|
125
|
+
|
|
126
|
+
The root `opencode.json` starts the installed package portably:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"lsp": {
|
|
131
|
+
"delphi": {
|
|
132
|
+
"command": ["delphi-lsp"],
|
|
133
|
+
"extensions": [".pas", ".dpr", ".dpk", ".inc"],
|
|
134
|
+
"initialization": {"autoDiscoverPaths": true}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`autoDiscoverPaths` is the default. It discovers compiler context without an
|
|
141
|
+
environment section; LSP remains available for normal editor and OpenCode use,
|
|
142
|
+
including large sources.
|
|
143
|
+
|
|
144
|
+
The LSP builds its structural index through the same optimized outline path for
|
|
145
|
+
every source, with no file-size threshold. Definition, hover, references,
|
|
146
|
+
rename, completion, document symbols, workspace symbols, and diagnostics remain
|
|
147
|
+
registered for every file size; source-aware fallbacks keep body-level queries
|
|
148
|
+
available without returning the complete file as agent context.
|
|
149
|
+
|
|
150
|
+
### Automatic discovery
|
|
151
|
+
|
|
152
|
+
Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files.
|
|
153
|
+
Its resolution order is:
|
|
154
|
+
|
|
155
|
+
1. An explicit project selection takes precedence.
|
|
156
|
+
2. Otherwise, `.dpr` and `.dpk` candidates are considered.
|
|
157
|
+
3. `MainSource` in a `.dproj` contributes its entry project.
|
|
158
|
+
4. A selected entry associates same-stem `.dproj`, `.cfg`, and `.dof`.
|
|
159
|
+
5. Unit search paths, include paths, and defines are accumulated from explicit
|
|
160
|
+
settings, project metadata, and the associated settings files.
|
|
161
|
+
6. Direct `Unit in 'path/Unit.pas'` references contribute their parent
|
|
162
|
+
directory to unit search paths.
|
|
163
|
+
|
|
164
|
+
A single discovered project is selected automatically. With no project entry,
|
|
165
|
+
the server uses a synthetic workspace of supported sources. Scans skip build
|
|
166
|
+
and cache directories such as `build`, `dist`, environments, VCS folders,
|
|
167
|
+
`node_modules`, and tool caches. Missing paths and invalid metadata become
|
|
168
|
+
problems; paths are not guessed.
|
|
169
|
+
|
|
170
|
+
## Agent CLI and Interface/Protocol v2
|
|
171
|
+
|
|
172
|
+
`delphi-lsp-agent` has these subcommands and options:
|
|
173
|
+
|
|
174
|
+
```text
|
|
175
|
+
delphi-lsp-agent view --root PATH [--project-file FILE] --layer LAYER
|
|
176
|
+
[--query TEXT] [--format markdown|json] [--deep-projects]
|
|
177
|
+
delphi-lsp-agent index --root PATH [--project-file FILE] [--out FILE]
|
|
178
|
+
delphi-lsp-agent skill install [--target PATH] [--force]
|
|
179
|
+
delphi-lsp-agent opencode install [--target PATH] [--python PYTHON]
|
|
180
|
+
[--force] [--write-config]
|
|
181
|
+
delphi-lsp-agent worker --root PATH [--project-file FILE]
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`view --layer` accepts `overview`, `projects`, `units`, `unit`,
|
|
185
|
+
`symbols`, `symbol`, `implementation`, `references`, `problems`, and
|
|
186
|
+
`metrics`. For example, `delphi-lsp-agent view --layer metrics --format json`
|
|
187
|
+
returns a project summary and detailed unit metric objects; `--query` filters
|
|
188
|
+
units by name or path.
|
|
189
|
+
`index` materializes overview, projects, and problems JSON. `skill install`
|
|
190
|
+
writes the skill; `opencode install` writes both integration files, while
|
|
191
|
+
`--write-config` additionally writes the restricted agent configuration.
|
|
192
|
+
`worker` serves NDJSON over standard input/output.
|
|
193
|
+
|
|
194
|
+
Protocol v2 actions are `open`, `find`, `inspect`, `trace`, `focus`,
|
|
195
|
+
`problems`, and `metrics`. A `metrics` request without a query returns the
|
|
196
|
+
project summary followed by unit cards. A query filters units, while a unit
|
|
197
|
+
`target_id` from `open` selects one unit; `detail: "members"` adds routine,
|
|
198
|
+
Halstead, dependency, and symbol-count detail without returning source text.
|
|
199
|
+
Detail values are `summary`, `declaration`, `members`,
|
|
200
|
+
`context`, `body`, and `implementations`. Relations are `references`,
|
|
201
|
+
`callers`, `callees`, `uses`, `used_by`, `inherits`, and
|
|
202
|
+
`implements`.
|
|
203
|
+
|
|
204
|
+
A request requires `action` and can include `query`, `target_id`,
|
|
205
|
+
`project_id`, `detail`, `relation`, `cursor`, `max_items`, and
|
|
206
|
+
`max_chars`. Defaults are empty text fields, `detail: "summary"`, no
|
|
207
|
+
relation, `max_items: 12`, and `max_chars: 12000`. Ranges are 1–50 items
|
|
208
|
+
and 256–40000 characters. A successful envelope has `schema: 2`,
|
|
209
|
+
`workspace_revision`, `focus` (project, unit, and target IDs), `result`,
|
|
210
|
+
`page`, and `context`; errors have `schema: 2` and a code/message.
|
|
211
|
+
|
|
212
|
+
Focus preserves the selected project, unit, or target. Cursors bind a workspace
|
|
213
|
+
revision and request fingerprint, so source changes and cross-target or
|
|
214
|
+
cross-detail reuse invalidate them. `max_items` and `max_chars` bound each
|
|
215
|
+
response. A `sound_partial` relation is sound but incomplete: unresolved and
|
|
216
|
+
ambiguous relations are never fabricated.
|
|
217
|
+
|
|
218
|
+
For every source size the navigator builds an outline first, loads source detail
|
|
219
|
+
lazily for a selected target, and returns only selected fragments. Typed source
|
|
220
|
+
chunks are at most 6000 characters and also respect the response budget. This
|
|
221
|
+
optimization does not remove LSP functionality.
|
|
222
|
+
|
|
223
|
+
## OpenCode semantic navigator
|
|
224
|
+
|
|
225
|
+
Install the generated integration in a worktree:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
delphi-lsp-agent opencode install --target . --write-config
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
It writes:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
.agents/skills/delphi-codebase-navigator/SKILL.md
|
|
235
|
+
.opencode/plugins/delphi_codebase.ts
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The generated configuration enables only the named
|
|
239
|
+
`delphi-codebase-navigator` skill and `delphi_codebase`. It denies
|
|
240
|
+
`bash`, `read`, `glob`, `grep`, and `lsp`, along with edit/write and
|
|
241
|
+
other raw source tools. The skill is enabled. The installer does not use the
|
|
242
|
+
retired `.opencode/tools` path.
|
|
243
|
+
|
|
244
|
+
The plugin maintains one worker per session/root, reusing focus and indexes.
|
|
245
|
+
During compaction it restores the focus and summary into the new context.
|
|
246
|
+
Transport failure, session deletion, and plugin disposal clean up the worker.
|
|
247
|
+
|
|
248
|
+
A generated OpenCode agent looks like this; providers and unrelated agents stay
|
|
249
|
+
unchanged:
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"agent": {
|
|
254
|
+
"vllm-delphi-codebase": {
|
|
255
|
+
"tools": {
|
|
256
|
+
"delphi_codebase": true, "skill": true, "lsp": false,
|
|
257
|
+
"bash": false, "read": false, "glob": false, "grep": false
|
|
258
|
+
},
|
|
259
|
+
"permission": {
|
|
260
|
+
"delphi_codebase": "allow",
|
|
261
|
+
"skill": {"*": "deny", "delphi-codebase-navigator": "allow"},
|
|
262
|
+
"lsp": "deny"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Select `vllm-delphi-codebase`, ask it to load
|
|
270
|
+
`delphi-codebase-navigator`, then use `delphi_codebase` actions such as
|
|
271
|
+
`open`, `find`, `focus`, and `inspect`. Use semantic tool calls, not raw
|
|
272
|
+
source tools.
|
|
273
|
+
|
|
274
|
+
For architecture questions, call `metrics` without a query to compare unit
|
|
275
|
+
cards and read project LOC. Then select a returned unit ID with another
|
|
276
|
+
`metrics` call and `detail: "members"` to inspect its routines and coupling.
|
|
277
|
+
|
|
278
|
+
For the root LSP configuration, a local model can be used as follows:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
opencode run --dir . --model ollama/ornith-lspctx --agent vllm-lsp \
|
|
282
|
+
"Find the declaration of a Delphi symbol through LSP."
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Use `--agent vllm-lsp-edit` only for the separate, focused LSP/edit
|
|
286
|
+
verification workflow; the semantic navigator agent above remains restricted
|
|
287
|
+
to its named skill and tool.
|
|
288
|
+
|
|
289
|
+
That separate verification uses `vllm/ornith-lspctx` and accepts the focused
|
|
290
|
+
LSP result `edit:Edit applied successfully`; it is not the semantic navigator
|
|
291
|
+
workflow and does not grant the navigator any raw source tools.
|
|
292
|
+
|
|
293
|
+
## Reproducible large-project vLLM proof
|
|
294
|
+
|
|
295
|
+
The proof generates a 117,511-line project. The verifier requires `skill`, `open` (`Main.dpr` evidence), `find`, `focus`, and `inspect`,
|
|
296
|
+
checks `MegaProc02500` and `Value := Value + 40`, and forbids raw `bash`,
|
|
297
|
+
`read`, `glob`, and `grep`. It then waits for the final answer and requires the
|
|
298
|
+
exact body range `src/Mega100kUnit.pas:117464-117509` and the inspected
|
|
299
|
+
statement in that answer. The prompt requires returned range metadata instead
|
|
300
|
+
of a model-calculated line inside the source fragment.
|
|
301
|
+
The proof uses the local Ornith vLLM OpenAI-compatible
|
|
302
|
+
endpoint at `http://127.0.0.1:8001/v1`.
|
|
303
|
+
|
|
304
|
+
Default scripts are offline and must not redownload the model. First check the
|
|
305
|
+
cache:
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
python scripts/check_ornith_cache.py --require-complete
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
With an already-running endpoint on any supported platform, run:
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
python scripts/bootstrap_vllm_codebase_skill_test.py --use-running-server
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
On macOS, the offline cached auto-start path is:
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
python scripts/bootstrap_vllm_codebase_skill_test.py --start-vllm
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Automatic local vLLM startup is macOS-only. The package and OpenCode plugin are
|
|
324
|
+
supported on Windows. On Windows, start an OpenAI-compatible vLLM endpoint, then
|
|
325
|
+
run the Python bootstrap from PowerShell:
|
|
326
|
+
|
|
327
|
+
```powershell
|
|
328
|
+
python .\scripts\bootstrap_vllm_codebase_skill_test.py --use-running-server
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
For an endpoint at another URL, add `--base-url`:
|
|
332
|
+
|
|
333
|
+
```powershell
|
|
334
|
+
python .\scripts\bootstrap_vllm_codebase_skill_test.py --use-running-server --base-url http://127.0.0.1:9000/v1
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
`--skip-install` is an optional acceleration for an already prepared `.venv`;
|
|
338
|
+
omit it on a clean checkout so the bootstrap installs `.[dev]`.
|
|
339
|
+
The final-answer verifier defaults to a 420-second probe timeout. On a slower
|
|
340
|
+
local model server, increase it explicitly with `--probe-timeout SECONDS`.
|
|
341
|
+
|
|
342
|
+
The bundled automatic helper is not a cross-platform startup mechanism.
|
|
343
|
+
|
|
344
|
+
The architecture-metrics proof uses a separate deterministic 34-LOC project.
|
|
345
|
+
It requires the restricted model to load the skill, call `metrics` for the
|
|
346
|
+
project and most-complex unit, and report exact LOC, cyclomatic maximum, and
|
|
347
|
+
instability values. Raw source, search, shell, and write tools remain forbidden:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
python scripts/bootstrap_vllm_codebase_skill_test.py --probe metrics --use-running-server
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Use `--probe metrics --start-vllm --max-model-len 24576` for the cached macOS
|
|
354
|
+
auto-start path when no endpoint is already running.
|
|
355
|
+
|
|
356
|
+
## Migration to 2.0
|
|
357
|
+
|
|
358
|
+
`delphi_lsp` is the only supported import namespace. Update imports directly;
|
|
359
|
+
there is no compatibility import alias.
|
|
360
|
+
|
|
361
|
+
## Verification and limitations
|
|
362
|
+
|
|
363
|
+
For a checkout:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
python -m pip install -e ".[dev]"
|
|
367
|
+
python -m pytest
|
|
368
|
+
python -m build
|
|
369
|
+
python -m twine check dist/*
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
CI tests Ubuntu, macOS, and Windows on Python 3.10 and 3.14, then builds and
|
|
373
|
+
smoke-installs the wheel on Ubuntu/Python 3.14. Results depend on available
|
|
374
|
+
project files, defines, includes, and paths; unsupported compiler behavior and
|
|
375
|
+
unresolvable references are reported as problems. The vLLM proof additionally
|
|
376
|
+
requires OpenCode, a local endpoint, and a complete local cache.
|
|
377
|
+
|
|
378
|
+
## License
|
|
379
|
+
|
|
380
|
+
Mozilla Public License 2.0. See [LICENSE](LICENSE).
|