python-delphi-lsp 1.0.1__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/MANIFEST.in +1 -0
  2. {python_delphi_lsp-1.0.1/python_delphi_lsp.egg-info → python_delphi_lsp-1.1.0}/PKG-INFO +107 -18
  3. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/README.md +106 -17
  4. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/__init__.py +4 -0
  5. python_delphi_lsp-1.1.0/delphiast/agent_cli.py +99 -0
  6. python_delphi_lsp-1.1.0/delphiast/agent_layers.py +331 -0
  7. python_delphi_lsp-1.1.0/delphiast/agent_templates.py +181 -0
  8. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/lsp_server.py +62 -3
  9. python_delphi_lsp-1.1.0/delphiast/project_discovery.py +375 -0
  10. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/opencode.json +1 -5
  11. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/pyproject.toml +2 -1
  12. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0/python_delphi_lsp.egg-info}/PKG-INFO +107 -18
  13. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/python_delphi_lsp.egg-info/SOURCES.txt +8 -0
  14. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/python_delphi_lsp.egg-info/entry_points.txt +1 -0
  15. python_delphi_lsp-1.1.0/scripts/bootstrap_vllm_codebase_skill_test.py +227 -0
  16. python_delphi_lsp-1.1.0/tests/test_agent_codebase.py +138 -0
  17. python_delphi_lsp-1.1.0/tests/test_bootstrap_vllm_codebase_skill.py +56 -0
  18. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_opencode_config.py +9 -0
  19. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_package_metadata.py +6 -2
  20. python_delphi_lsp-1.1.0/tests/test_project_discovery.py +174 -0
  21. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/LICENSE +0 -0
  22. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/binary.py +0 -0
  23. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/comment_builder.py +0 -0
  24. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/consts.py +0 -0
  25. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/grammar.py +0 -0
  26. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/lark_builder.py +0 -0
  27. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/lark_tokens.py +0 -0
  28. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/nodes.py +0 -0
  29. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/parser.py +0 -0
  30. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/preprocessor.py +0 -0
  31. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/project_indexer.py +0 -0
  32. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/semantic.py +0 -0
  33. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/semantic_builder.py +0 -0
  34. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/source_reader.py +0 -0
  35. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/workspace.py +0 -0
  36. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/delphiast/writer.py +0 -0
  37. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
  38. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/python_delphi_lsp.egg-info/requires.txt +0 -0
  39. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/python_delphi_lsp.egg-info/top_level.txt +0 -0
  40. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/audit_delphi_language_features.py +0 -0
  41. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
  42. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/bootstrap_vllm_opencode_test.py +0 -0
  43. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
  44. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/check_ornith_cache.py +0 -0
  45. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/generate_release_evidence.py +0 -0
  46. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
  47. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/prepare_ornith_cache.py +0 -0
  48. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/run_opencode_lsp_probe.py +0 -0
  49. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/start_ornith_vllm.sh +0 -0
  50. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/scripts/summarize_opencode_request_payloads.py +0 -0
  51. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/setup.cfg +0 -0
  52. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
  53. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
  54. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
  55. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/constset.pas +0 -0
  56. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
  57. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
  58. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
  59. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
  60. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
  61. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
  62. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
  63. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
  64. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
  65. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
  66. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
  67. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
  68. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
  69. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
  70. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
  71. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
  72. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
  73. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
  74. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
  75. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
  76. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/properties.pas +0 -0
  77. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
  78. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
  79. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
  80. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
  81. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/library_demo.dpr +0 -0
  82. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/package_demo.dpk +0 -0
  83. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/program_demo.dpr +0 -0
  84. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_advanced.pas +0 -0
  85. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_attributes.pas +0 -0
  86. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_basic.pas +0 -0
  87. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_consumer.pas +0 -0
  88. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_generics.pas +0 -0
  89. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_inheritance.pas +0 -0
  90. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_math.pas +0 -0
  91. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_properties.pas +0 -0
  92. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_sections.pas +0 -0
  93. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_statements.pas +0 -0
  94. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_types.pas +0 -0
  95. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_unresolved.pas +0 -0
  96. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/fixtures/unit_with.pas +0 -0
  97. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_bootstrap_vllm_opencode.py +0 -0
  98. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_diagnostics.py +0 -0
  99. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_language_feature_matrix.py +0 -0
  100. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_legacy_snippets.py +0 -0
  101. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_lsp_features.py +0 -0
  102. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_lsp_support.py +0 -0
  103. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_opencode_probe.py +0 -0
  104. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_opencode_request_payloads.py +0 -0
  105. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_ornith_cache_prepare.py +0 -0
  106. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_parser.py +0 -0
  107. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_preprocessor.py +0 -0
  108. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_project_indexer.py +0 -0
  109. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_release_evidence.py +0 -0
  110. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_semantic.py +0 -0
  111. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_vllm_start_script.py +0 -0
  112. {python_delphi_lsp-1.0.1 → python_delphi_lsp-1.1.0}/tests/test_workspace.py +0 -0
@@ -4,6 +4,7 @@ include opencode.json
4
4
  include scripts/check_ornith_cache.py
5
5
  include scripts/audit_delphi_language_features.py
6
6
  include scripts/bootstrap_vllm_opencode_test.py
7
+ include scripts/bootstrap_vllm_codebase_skill_test.py
7
8
  include scripts/bootstrap_vllm_opencode_test.ps1
8
9
  include scripts/bootstrap_vllm_opencode_test.sh
9
10
  include scripts/generate_release_evidence.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-delphi-lsp
3
- Version: 1.0.1
3
+ Version: 1.1.0
4
4
  Summary: Python Delphi/Object Pascal parser, semantic indexer, and language server.
5
5
  Author: Dark Light
6
6
  License-Expression: MPL-2.0
@@ -43,8 +43,9 @@ Python Delphi LSP is a standalone Python package for Delphi/Object Pascal
43
43
  parsing, semantic indexing, diagnostics, and Language Server Protocol support.
44
44
 
45
45
  The distributable package is named `python-delphi-lsp`. The import package keeps
46
- the established `delphiast` name, and the language-server executable is
47
- `delphi-lsp`.
46
+ the established `delphiast` name. The language-server executable is
47
+ `delphi-lsp`, and the agent-facing codebase navigator executable is
48
+ `delphi-lsp-agent`.
48
49
 
49
50
  ## What It Provides
50
51
 
@@ -56,7 +57,10 @@ the established `delphiast` name, and the language-server executable is
56
57
  - Workspace indexing across Delphi projects
57
58
  - LSP support for document symbols, workspace symbols, hover, definition,
58
59
  references, rename, completion, and diagnostics
59
- - opencode integration through the experimental LSP tool
60
+ - Automatic project path discovery from `.dpr`, `.dpk`, `.dproj`, `.cfg`, and
61
+ `.dof` files
62
+ - opencode integration through the experimental LSP tool and an installable
63
+ `.agents` skill with a dedicated codebase-inspection tool
60
64
 
61
65
  ## Installation
62
66
 
@@ -138,17 +142,71 @@ python -m delphiast.lsp_server
138
142
  ```
139
143
 
140
144
  The server expects normal LSP JSON-RPC over stdio. Editors and tools should set
141
- the workspace root to the Delphi project directory and pass any include paths or
142
- compiler defines through LSP initialization options when needed.
145
+ the workspace root to the Delphi project directory.
146
+
147
+ Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files to
148
+ collect unit search paths, include paths, defines, direct `Unit in 'path.pas'`
149
+ references, and workspace source directories. Manual initialization options are
150
+ still accepted as overrides, but a normal project should not require users to
151
+ set include or source paths by hand.
152
+
153
+ ```json
154
+ {
155
+ "$schema": "https://opencode.ai/config.json",
156
+ "lsp": {
157
+ "delphi": {
158
+ "command": ["python", "-m", "delphiast.lsp_server"],
159
+ "extensions": [".pas", ".dpr", ".dpk", ".inc"],
160
+ "initialization": {
161
+ "autoDiscoverPaths": true
162
+ }
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ ## Agent Codebase Navigator
169
+
170
+ Install the opencode skill and custom tool in a Delphi checkout:
171
+
172
+ ```bash
173
+ delphi-lsp-agent opencode install --target . --write-config
174
+ ```
175
+
176
+ This writes:
177
+
178
+ - `.agents/skills/delphi-codebase-navigator/SKILL.md`
179
+ - `.opencode/tools/delphi_codebase.ts`
180
+ - an optional `vllm-delphi-codebase` agent entry in `opencode.json`
181
+
182
+ The skill tells agents to inspect Delphi code through layered semantic views
183
+ instead of loading full source files. The custom opencode tool calls
184
+ `python -m delphiast.agent_cli` directly, so the agent does not need shell text
185
+ search or raw file-reading tools to understand the codebase.
186
+
187
+ Useful direct commands:
188
+
189
+ ```bash
190
+ delphi-lsp-agent view --root . --layer overview
191
+ delphi-lsp-agent view --root . --layer projects
192
+ delphi-lsp-agent view --root . --layer unit --query Mega100kUnit
193
+ delphi-lsp-agent view --root . --layer symbols --query TWorker --format json
194
+ delphi-lsp-agent view --root . --layer problems
195
+ ```
196
+
197
+ Available layers are `overview`, `projects`, `units`, `unit`, `symbols`,
198
+ `symbol`, `references`, and `problems`. The output includes file and line
199
+ citations, declarations, ownership, visibility, type information, and
200
+ dependency/problem summaries. Routine bodies are not emitted.
143
201
 
144
202
  ## opencode Usage
145
203
 
146
204
  This repository includes an `opencode.json` that registers the Delphi LSP tool
147
205
  and model aliases for local Ollama and vLLM endpoints.
148
206
 
149
- To add the Delphi language server to another opencode project, install the
150
- package in the Python environment used by opencode and add an `lsp.delphi`
151
- entry to that project's `opencode.json`:
207
+ To add the Delphi language server to another opencode project without the
208
+ agent tool, install the package in the Python environment used by opencode and
209
+ add an `lsp.delphi` entry to that project's `opencode.json`:
152
210
 
153
211
  ```json
154
212
  {
@@ -158,17 +216,16 @@ entry to that project's `opencode.json`:
158
216
  "command": ["python", "-m", "delphiast.lsp_server"],
159
217
  "extensions": [".pas", ".dpr", ".dpk", ".inc"],
160
218
  "initialization": {
161
- "includePaths": ["src", "lib"],
162
- "defines": ["MSWINDOWS"]
219
+ "autoDiscoverPaths": true
163
220
  }
164
221
  }
165
222
  }
166
223
  }
167
224
  ```
168
225
 
169
- Adjust `includePaths` and `defines` to match the Delphi project. For checkout
170
- development, this repository's own `opencode.json` uses the local virtual
171
- environment and sets `PYTHONPATH` so opencode loads the source tree directly:
226
+ For checkout development, this repository's own `opencode.json` uses the local
227
+ virtual environment and sets `PYTHONPATH` so opencode loads the source tree
228
+ directly:
172
229
 
173
230
  ```json
174
231
  {
@@ -180,8 +237,7 @@ environment and sets `PYTHONPATH` so opencode loads the source tree directly:
180
237
  "PYTHONPATH": "."
181
238
  },
182
239
  "initialization": {
183
- "includePaths": ["tests/fixtures", "tests/fixtures/legacy_snippets"],
184
- "defines": []
240
+ "autoDiscoverPaths": true
185
241
  }
186
242
  }
187
243
  }
@@ -299,6 +355,39 @@ The release evidence from the local proof recorded:
299
355
  - `context_budget.status = "pass"`
300
356
  - `goal_audit.status = "pass"`
301
357
 
358
+ ## Reproducing the vLLM opencode Skill Test
359
+
360
+ The codebase skill proof validates the `.agents` skill and opencode custom tool
361
+ instead of only the raw LSP tool. It creates a sandbox Delphi project with:
362
+
363
+ - `Main.dpr`
364
+ - `Main.dproj`
365
+ - `src/Mega100kUnit.pas` with more than 100,000 lines
366
+ - `include/build.inc`
367
+ - `.agents/skills/delphi-codebase-navigator/SKILL.md`
368
+ - `.opencode/tools/delphi_codebase.ts`
369
+
370
+ Run it against the local Ornith vLLM endpoint:
371
+
372
+ ```bash
373
+ python scripts/bootstrap_vllm_codebase_skill_test.py --use-running-server
374
+ ```
375
+
376
+ Or let the macOS helper start vLLM without downloading model shards:
377
+
378
+ ```bash
379
+ python scripts/bootstrap_vllm_codebase_skill_test.py --start-vllm
380
+ ```
381
+
382
+ This skill probe defaults the vLLM helper to `MAX_MODEL_LEN=32768`, which was
383
+ the stable local Metal setting for the complete skill + `delphi_codebase` tool
384
+ call. Override with `--max-model-len` when your machine has enough headroom.
385
+
386
+ The probe requires opencode to load `delphi-codebase-navigator`, call
387
+ `delphi_codebase`, and find `MegaProc02500`. It fails if opencode uses `bash`,
388
+ `read`, `glob`, `grep`, `edit`, `write`, `task`, `webfetch`, or `todowrite`
389
+ before the required evidence is complete.
390
+
302
391
  ## Verification
303
392
 
304
393
  Run the local test suite:
@@ -322,8 +411,8 @@ python -m twine check dist/*
322
411
 
323
412
  ## Repository Layout
324
413
 
325
- - `delphiast/` - parser, preprocessor, semantic model, workspace indexer, and
326
- LSP server
414
+ - `delphiast/` - parser, preprocessor, project discovery, semantic model,
415
+ workspace indexer, agent layers, and LSP server
327
416
  - `scripts/` - release evidence, cache checks, opencode probes, and bootstrap
328
417
  helpers
329
418
  - `tests/` - parser, semantic, workspace, diagnostics, packaging, and LSP tests
@@ -4,8 +4,9 @@ Python Delphi LSP is a standalone Python package for Delphi/Object Pascal
4
4
  parsing, semantic indexing, diagnostics, and Language Server Protocol support.
5
5
 
6
6
  The distributable package is named `python-delphi-lsp`. The import package keeps
7
- the established `delphiast` name, and the language-server executable is
8
- `delphi-lsp`.
7
+ the established `delphiast` name. The language-server executable is
8
+ `delphi-lsp`, and the agent-facing codebase navigator executable is
9
+ `delphi-lsp-agent`.
9
10
 
10
11
  ## What It Provides
11
12
 
@@ -17,7 +18,10 @@ the established `delphiast` name, and the language-server executable is
17
18
  - Workspace indexing across Delphi projects
18
19
  - LSP support for document symbols, workspace symbols, hover, definition,
19
20
  references, rename, completion, and diagnostics
20
- - opencode integration through the experimental LSP tool
21
+ - Automatic project path discovery from `.dpr`, `.dpk`, `.dproj`, `.cfg`, and
22
+ `.dof` files
23
+ - opencode integration through the experimental LSP tool and an installable
24
+ `.agents` skill with a dedicated codebase-inspection tool
21
25
 
22
26
  ## Installation
23
27
 
@@ -99,17 +103,71 @@ python -m delphiast.lsp_server
99
103
  ```
100
104
 
101
105
  The server expects normal LSP JSON-RPC over stdio. Editors and tools should set
102
- the workspace root to the Delphi project directory and pass any include paths or
103
- compiler defines through LSP initialization options when needed.
106
+ the workspace root to the Delphi project directory.
107
+
108
+ Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files to
109
+ collect unit search paths, include paths, defines, direct `Unit in 'path.pas'`
110
+ references, and workspace source directories. Manual initialization options are
111
+ still accepted as overrides, but a normal project should not require users to
112
+ set include or source paths by hand.
113
+
114
+ ```json
115
+ {
116
+ "$schema": "https://opencode.ai/config.json",
117
+ "lsp": {
118
+ "delphi": {
119
+ "command": ["python", "-m", "delphiast.lsp_server"],
120
+ "extensions": [".pas", ".dpr", ".dpk", ".inc"],
121
+ "initialization": {
122
+ "autoDiscoverPaths": true
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ ## Agent Codebase Navigator
130
+
131
+ Install the opencode skill and custom tool in a Delphi checkout:
132
+
133
+ ```bash
134
+ delphi-lsp-agent opencode install --target . --write-config
135
+ ```
136
+
137
+ This writes:
138
+
139
+ - `.agents/skills/delphi-codebase-navigator/SKILL.md`
140
+ - `.opencode/tools/delphi_codebase.ts`
141
+ - an optional `vllm-delphi-codebase` agent entry in `opencode.json`
142
+
143
+ The skill tells agents to inspect Delphi code through layered semantic views
144
+ instead of loading full source files. The custom opencode tool calls
145
+ `python -m delphiast.agent_cli` directly, so the agent does not need shell text
146
+ search or raw file-reading tools to understand the codebase.
147
+
148
+ Useful direct commands:
149
+
150
+ ```bash
151
+ delphi-lsp-agent view --root . --layer overview
152
+ delphi-lsp-agent view --root . --layer projects
153
+ delphi-lsp-agent view --root . --layer unit --query Mega100kUnit
154
+ delphi-lsp-agent view --root . --layer symbols --query TWorker --format json
155
+ delphi-lsp-agent view --root . --layer problems
156
+ ```
157
+
158
+ Available layers are `overview`, `projects`, `units`, `unit`, `symbols`,
159
+ `symbol`, `references`, and `problems`. The output includes file and line
160
+ citations, declarations, ownership, visibility, type information, and
161
+ dependency/problem summaries. Routine bodies are not emitted.
104
162
 
105
163
  ## opencode Usage
106
164
 
107
165
  This repository includes an `opencode.json` that registers the Delphi LSP tool
108
166
  and model aliases for local Ollama and vLLM endpoints.
109
167
 
110
- To add the Delphi language server to another opencode project, install the
111
- package in the Python environment used by opencode and add an `lsp.delphi`
112
- entry to that project's `opencode.json`:
168
+ To add the Delphi language server to another opencode project without the
169
+ agent tool, install the package in the Python environment used by opencode and
170
+ add an `lsp.delphi` entry to that project's `opencode.json`:
113
171
 
114
172
  ```json
115
173
  {
@@ -119,17 +177,16 @@ entry to that project's `opencode.json`:
119
177
  "command": ["python", "-m", "delphiast.lsp_server"],
120
178
  "extensions": [".pas", ".dpr", ".dpk", ".inc"],
121
179
  "initialization": {
122
- "includePaths": ["src", "lib"],
123
- "defines": ["MSWINDOWS"]
180
+ "autoDiscoverPaths": true
124
181
  }
125
182
  }
126
183
  }
127
184
  }
128
185
  ```
129
186
 
130
- Adjust `includePaths` and `defines` to match the Delphi project. For checkout
131
- development, this repository's own `opencode.json` uses the local virtual
132
- environment and sets `PYTHONPATH` so opencode loads the source tree directly:
187
+ For checkout development, this repository's own `opencode.json` uses the local
188
+ virtual environment and sets `PYTHONPATH` so opencode loads the source tree
189
+ directly:
133
190
 
134
191
  ```json
135
192
  {
@@ -141,8 +198,7 @@ environment and sets `PYTHONPATH` so opencode loads the source tree directly:
141
198
  "PYTHONPATH": "."
142
199
  },
143
200
  "initialization": {
144
- "includePaths": ["tests/fixtures", "tests/fixtures/legacy_snippets"],
145
- "defines": []
201
+ "autoDiscoverPaths": true
146
202
  }
147
203
  }
148
204
  }
@@ -260,6 +316,39 @@ The release evidence from the local proof recorded:
260
316
  - `context_budget.status = "pass"`
261
317
  - `goal_audit.status = "pass"`
262
318
 
319
+ ## Reproducing the vLLM opencode Skill Test
320
+
321
+ The codebase skill proof validates the `.agents` skill and opencode custom tool
322
+ instead of only the raw LSP tool. It creates a sandbox Delphi project with:
323
+
324
+ - `Main.dpr`
325
+ - `Main.dproj`
326
+ - `src/Mega100kUnit.pas` with more than 100,000 lines
327
+ - `include/build.inc`
328
+ - `.agents/skills/delphi-codebase-navigator/SKILL.md`
329
+ - `.opencode/tools/delphi_codebase.ts`
330
+
331
+ Run it against the local Ornith vLLM endpoint:
332
+
333
+ ```bash
334
+ python scripts/bootstrap_vllm_codebase_skill_test.py --use-running-server
335
+ ```
336
+
337
+ Or let the macOS helper start vLLM without downloading model shards:
338
+
339
+ ```bash
340
+ python scripts/bootstrap_vllm_codebase_skill_test.py --start-vllm
341
+ ```
342
+
343
+ This skill probe defaults the vLLM helper to `MAX_MODEL_LEN=32768`, which was
344
+ the stable local Metal setting for the complete skill + `delphi_codebase` tool
345
+ call. Override with `--max-model-len` when your machine has enough headroom.
346
+
347
+ The probe requires opencode to load `delphi-codebase-navigator`, call
348
+ `delphi_codebase`, and find `MegaProc02500`. It fails if opencode uses `bash`,
349
+ `read`, `glob`, `grep`, `edit`, `write`, `task`, `webfetch`, or `todowrite`
350
+ before the required evidence is complete.
351
+
263
352
  ## Verification
264
353
 
265
354
  Run the local test suite:
@@ -283,8 +372,8 @@ python -m twine check dist/*
283
372
 
284
373
  ## Repository Layout
285
374
 
286
- - `delphiast/` - parser, preprocessor, semantic model, workspace indexer, and
287
- LSP server
375
+ - `delphiast/` - parser, preprocessor, project discovery, semantic model,
376
+ workspace indexer, agent layers, and LSP server
288
377
  - `scripts/` - release evidence, cache checks, opencode probes, and bootstrap
289
378
  helpers
290
379
  - `tests/` - parser, semantic, workspace, diagnostics, packaging, and LSP tests
@@ -46,6 +46,7 @@ from .semantic import (
46
46
  from .semantic_builder import SemanticBuilder, SemanticModel, SemanticProblem
47
47
  from .workspace import WorkspaceSemanticResult, build_workspace_semantics
48
48
  from .lsp_server import LspWorkspaceState, create_server
49
+ from .project_discovery import DelphiProjectDiscovery, DiscoveryProblem, discover_delphi_project
49
50
  from .project_indexer import (
50
51
  GetUnitSyntaxHook,
51
52
  IncludeFileInfo,
@@ -119,6 +120,9 @@ __all__ = [
119
120
  'build_workspace_semantics',
120
121
  'LspWorkspaceState',
121
122
  'create_server',
123
+ 'DelphiProjectDiscovery',
124
+ 'DiscoveryProblem',
125
+ 'discover_delphi_project',
122
126
  'ProjectIndexer',
123
127
  'ProjectIndexResult',
124
128
  'ProjectProblemType',
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from .agent_layers import build_codebase_index, layer_payload, render_layer
9
+ from .agent_templates import install_opencode_support, install_skill
10
+
11
+
12
+ def build_parser() -> argparse.ArgumentParser:
13
+ parser = argparse.ArgumentParser(
14
+ prog="delphi-lsp-agent",
15
+ description="Agent-facing Delphi/Object Pascal codebase navigation helpers.",
16
+ )
17
+ subcommands = parser.add_subparsers(dest="command", required=True)
18
+
19
+ view = subcommands.add_parser("view", help="Render a layered codebase view.")
20
+ view.add_argument("--root", type=Path, default=Path("."))
21
+ view.add_argument("--project-file", type=Path)
22
+ view.add_argument("--layer", required=True, choices=["overview", "projects", "units", "unit", "symbols", "symbol", "references", "problems"])
23
+ view.add_argument("--query", default="")
24
+ view.add_argument("--format", default="markdown", choices=["markdown", "json"])
25
+ view.add_argument("--deep-projects", action="store_true", help="Deep-parse project dependencies for the projects layer.")
26
+ view.set_defaults(func=_view)
27
+
28
+ index = subcommands.add_parser("index", help="Materialize a JSON codebase index.")
29
+ index.add_argument("--root", type=Path, default=Path("."))
30
+ index.add_argument("--project-file", type=Path)
31
+ index.add_argument("--out", type=Path, default=Path(".delphi-lsp") / "agent-index" / "index.json")
32
+ index.set_defaults(func=_index)
33
+
34
+ skill = subcommands.add_parser("skill", help="Install agent skill templates.")
35
+ skill_commands = skill.add_subparsers(dest="skill_command", required=True)
36
+ skill_install = skill_commands.add_parser("install", help="Install .agents skill.")
37
+ skill_install.add_argument("--target", type=Path, default=Path("."))
38
+ skill_install.add_argument("--force", action="store_true")
39
+ skill_install.set_defaults(func=_skill_install)
40
+
41
+ opencode = subcommands.add_parser("opencode", help="Install opencode integration.")
42
+ opencode_commands = opencode.add_subparsers(dest="opencode_command", required=True)
43
+ opencode_install = opencode_commands.add_parser("install", help="Install .agents skill and opencode custom tool.")
44
+ opencode_install.add_argument("--target", type=Path, default=Path("."))
45
+ opencode_install.add_argument("--python", default=sys.executable)
46
+ opencode_install.add_argument("--force", action="store_true")
47
+ opencode_install.add_argument("--write-config", action="store_true")
48
+ opencode_install.set_defaults(func=_opencode_install)
49
+
50
+ return parser
51
+
52
+
53
+ def main(argv: list[str] | None = None) -> int:
54
+ parser = build_parser()
55
+ args = parser.parse_args(argv)
56
+ try:
57
+ args.func(args)
58
+ except BrokenPipeError:
59
+ return 1
60
+ return 0
61
+
62
+
63
+ def _view(args: argparse.Namespace) -> None:
64
+ index = build_codebase_index(args.root, project_file=args.project_file, index_projects=args.deep_projects)
65
+ sys.stdout.write(render_layer(index, args.layer, query=args.query, output_format=args.format))
66
+
67
+
68
+ def _index(args: argparse.Namespace) -> None:
69
+ index = build_codebase_index(args.root, project_file=args.project_file, index_projects=True)
70
+ payload = {
71
+ "overview": layer_payload(index, "overview"),
72
+ "projects": layer_payload(index, "projects"),
73
+ "problems": layer_payload(index, "problems"),
74
+ }
75
+ args.out.parent.mkdir(parents=True, exist_ok=True)
76
+ args.out.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
77
+ print(args.out)
78
+
79
+
80
+ def _skill_install(args: argparse.Namespace) -> None:
81
+ skill_path = install_skill(args.target, force=args.force)
82
+ print(skill_path)
83
+
84
+
85
+ def _opencode_install(args: argparse.Namespace) -> None:
86
+ skill_path, tool_path, config_path = install_opencode_support(
87
+ args.target,
88
+ python_executable=args.python,
89
+ force=args.force,
90
+ write_config=args.write_config,
91
+ )
92
+ print(skill_path)
93
+ print(tool_path)
94
+ if config_path is not None:
95
+ print(config_path)
96
+
97
+
98
+ if __name__ == "__main__":
99
+ raise SystemExit(main())