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.
Files changed (140) hide show
  1. python_delphi_lsp-2.0.1/PKG-INFO +380 -0
  2. python_delphi_lsp-2.0.1/README.md +341 -0
  3. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/__init__.py +22 -0
  4. python_delphi_lsp-2.0.1/delphi_lsp/_version.py +1 -0
  5. python_delphi_lsp-2.0.1/delphi_lsp/agent_cli.py +243 -0
  6. python_delphi_lsp-2.0.1/delphi_lsp/agent_context.py +2138 -0
  7. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/agent_layers.py +67 -2
  8. python_delphi_lsp-2.0.1/delphi_lsp/agent_metrics.py +82 -0
  9. python_delphi_lsp-2.0.1/delphi_lsp/agent_protocol.py +391 -0
  10. python_delphi_lsp-2.0.1/delphi_lsp/agent_relations.py +859 -0
  11. python_delphi_lsp-2.0.1/delphi_lsp/agent_templates.py +580 -0
  12. python_delphi_lsp-2.0.1/delphi_lsp/agent_workspace.py +695 -0
  13. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/lark_builder.py +14 -2
  14. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/lsp_server.py +270 -48
  15. python_delphi_lsp-2.0.1/delphi_lsp/metrics.py +759 -0
  16. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/project_discovery.py +183 -40
  17. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/project_indexer.py +6 -0
  18. python_delphi_lsp-2.0.1/delphi_lsp/source_reader.py +17 -0
  19. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/workspace.py +15 -1
  20. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/opencode.json +1 -6
  21. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/pyproject.toml +5 -5
  22. python_delphi_lsp-2.0.1/python_delphi_lsp.egg-info/PKG-INFO +380 -0
  23. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/python_delphi_lsp.egg-info/SOURCES.txt +35 -21
  24. python_delphi_lsp-2.0.1/python_delphi_lsp.egg-info/entry_points.txt +3 -0
  25. python_delphi_lsp-2.0.1/python_delphi_lsp.egg-info/top_level.txt +1 -0
  26. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/audit_delphi_language_features.py +3 -3
  27. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_codebase_skill_test.py +227 -18
  28. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_opencode_test.py +1 -1
  29. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/generate_release_evidence.py +67 -19
  30. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/run_opencode_lsp_probe.py +133 -37
  31. python_delphi_lsp-2.0.1/tests/test_agent_codebase.py +958 -0
  32. python_delphi_lsp-2.0.1/tests/test_agent_context.py +1773 -0
  33. python_delphi_lsp-2.0.1/tests/test_agent_metrics.py +149 -0
  34. python_delphi_lsp-2.0.1/tests/test_agent_protocol.py +676 -0
  35. python_delphi_lsp-2.0.1/tests/test_agent_relations.py +1197 -0
  36. python_delphi_lsp-2.0.1/tests/test_agent_worker.py +448 -0
  37. python_delphi_lsp-2.0.1/tests/test_agent_workspace.py +1280 -0
  38. python_delphi_lsp-2.0.1/tests/test_bootstrap_vllm_codebase_skill.py +209 -0
  39. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_bootstrap_vllm_opencode.py +54 -9
  40. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_diagnostics.py +1 -1
  41. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_legacy_snippets.py +1 -1
  42. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_lsp_features.py +3 -3
  43. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_lsp_support.py +483 -18
  44. python_delphi_lsp-2.0.1/tests/test_metrics.py +188 -0
  45. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_opencode_probe.py +253 -0
  46. python_delphi_lsp-2.0.1/tests/test_package_metadata.py +137 -0
  47. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_parser.py +52 -2
  48. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_preprocessor.py +2 -2
  49. python_delphi_lsp-2.0.1/tests/test_project_discovery.py +427 -0
  50. python_delphi_lsp-2.0.1/tests/test_project_indexer.py +398 -0
  51. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_release_evidence.py +33 -3
  52. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_semantic.py +2 -2
  53. python_delphi_lsp-2.0.1/tests/test_workspace.py +85 -0
  54. python_delphi_lsp-1.1.1/PKG-INFO +0 -434
  55. python_delphi_lsp-1.1.1/README.md +0 -395
  56. python_delphi_lsp-1.1.1/delphiast/agent_cli.py +0 -113
  57. python_delphi_lsp-1.1.1/delphiast/agent_templates.py +0 -180
  58. python_delphi_lsp-1.1.1/delphiast/source_reader.py +0 -15
  59. python_delphi_lsp-1.1.1/python_delphi_lsp.egg-info/PKG-INFO +0 -434
  60. python_delphi_lsp-1.1.1/python_delphi_lsp.egg-info/entry_points.txt +0 -3
  61. python_delphi_lsp-1.1.1/python_delphi_lsp.egg-info/top_level.txt +0 -1
  62. python_delphi_lsp-1.1.1/tests/test_agent_codebase.py +0 -217
  63. python_delphi_lsp-1.1.1/tests/test_bootstrap_vllm_codebase_skill.py +0 -68
  64. python_delphi_lsp-1.1.1/tests/test_package_metadata.py +0 -57
  65. python_delphi_lsp-1.1.1/tests/test_project_discovery.py +0 -174
  66. python_delphi_lsp-1.1.1/tests/test_project_indexer.py +0 -152
  67. python_delphi_lsp-1.1.1/tests/test_workspace.py +0 -31
  68. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/LICENSE +0 -0
  69. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/MANIFEST.in +0 -0
  70. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/binary.py +0 -0
  71. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/comment_builder.py +0 -0
  72. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/consts.py +0 -0
  73. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/grammar.py +0 -0
  74. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/lark_tokens.py +0 -0
  75. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/nodes.py +0 -0
  76. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/parser.py +0 -0
  77. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/preprocessor.py +0 -0
  78. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/semantic.py +0 -0
  79. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/semantic_builder.py +0 -0
  80. {python_delphi_lsp-1.1.1/delphiast → python_delphi_lsp-2.0.1/delphi_lsp}/writer.py +0 -0
  81. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
  82. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/python_delphi_lsp.egg-info/requires.txt +0 -0
  83. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
  84. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
  85. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/check_ornith_cache.py +0 -0
  86. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
  87. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/prepare_ornith_cache.py +0 -0
  88. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/start_ornith_vllm.sh +0 -0
  89. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/scripts/summarize_opencode_request_payloads.py +0 -0
  90. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/setup.cfg +0 -0
  91. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
  92. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
  93. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
  94. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/constset.pas +0 -0
  95. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
  96. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
  97. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
  98. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
  99. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
  100. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
  101. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
  102. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
  103. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
  104. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
  105. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
  106. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
  107. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
  108. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
  109. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
  110. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
  111. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
  112. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
  113. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
  114. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
  115. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/properties.pas +0 -0
  116. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
  117. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
  118. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
  119. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
  120. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/library_demo.dpr +0 -0
  121. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/package_demo.dpk +0 -0
  122. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/program_demo.dpr +0 -0
  123. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_advanced.pas +0 -0
  124. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_attributes.pas +0 -0
  125. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_basic.pas +0 -0
  126. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_consumer.pas +0 -0
  127. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_generics.pas +0 -0
  128. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_inheritance.pas +0 -0
  129. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_math.pas +0 -0
  130. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_properties.pas +0 -0
  131. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_sections.pas +0 -0
  132. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_statements.pas +0 -0
  133. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_types.pas +0 -0
  134. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_unresolved.pas +0 -0
  135. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/fixtures/unit_with.pas +0 -0
  136. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_language_feature_matrix.py +0 -0
  137. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_opencode_config.py +0 -0
  138. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_opencode_request_payloads.py +0 -0
  139. {python_delphi_lsp-1.1.1 → python_delphi_lsp-2.0.1}/tests/test_ornith_cache_prepare.py +0 -0
  140. {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).