python-delphi-lsp 2.3.1__tar.gz → 2.3.3__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 (154) hide show
  1. {python_delphi_lsp-2.3.1/python_delphi_lsp.egg-info → python_delphi_lsp-2.3.3}/PKG-INFO +38 -9
  2. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/README.md +37 -8
  3. python_delphi_lsp-2.3.3/delphi_lsp/_version.py +1 -0
  4. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_cache.py +63 -16
  5. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_cli.py +8 -1
  6. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_context.py +3 -1
  7. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_templates.py +1 -1
  8. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_workspace.py +23 -2
  9. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/project_discovery.py +89 -4
  10. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/pyproject.toml +1 -1
  11. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3/python_delphi_lsp.egg-info}/PKG-INFO +38 -9
  12. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_cache.py +206 -0
  13. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_cli_errors.py +12 -0
  14. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_codebase.py +1 -0
  15. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_context.py +22 -11
  16. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_worker.py +50 -0
  17. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_workspace.py +57 -7
  18. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_package_metadata.py +3 -3
  19. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_project_discovery.py +73 -0
  20. python_delphi_lsp-2.3.1/delphi_lsp/_version.py +0 -1
  21. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/.github/workflows/ci.yml +0 -0
  22. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/LICENSE +0 -0
  23. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/MANIFEST.in +0 -0
  24. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/__init__.py +0 -0
  25. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_layers.py +0 -0
  26. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_metrics.py +0 -0
  27. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_protocol.py +0 -0
  28. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_relations.py +0 -0
  29. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/binary.py +0 -0
  30. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/comment_builder.py +0 -0
  31. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/consts.py +0 -0
  32. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/delphiast_lexer.py +0 -0
  33. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/delphiast_parser.py +0 -0
  34. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/delphiast_tokens.py +0 -0
  35. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/grammar.py +0 -0
  36. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/lark_builder.py +0 -0
  37. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/lark_tokens.py +0 -0
  38. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/lsp_server.py +0 -0
  39. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/metrics.py +0 -0
  40. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/navigation_cache.py +0 -0
  41. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/nodes.py +0 -0
  42. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/parallel_outline.py +0 -0
  43. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/parser.py +0 -0
  44. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/parser_backend.py +0 -0
  45. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/preprocessor.py +0 -0
  46. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/progress.py +0 -0
  47. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/project_indexer.py +0 -0
  48. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/semantic.py +0 -0
  49. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/semantic_builder.py +0 -0
  50. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/source_reader.py +0 -0
  51. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/workspace.py +0 -0
  52. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/delphi_lsp/writer.py +0 -0
  53. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/opencode.json +0 -0
  54. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/SOURCES.txt +0 -0
  55. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
  56. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/entry_points.txt +0 -0
  57. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/requires.txt +0 -0
  58. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/top_level.txt +0 -0
  59. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/audit_delphi_language_features.py +0 -0
  60. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/benchmark_github_corpus.py +0 -0
  61. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/benchmark_parallel_cache.py +0 -0
  62. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_codebase_skill_test.py +0 -0
  63. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
  64. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_opencode_test.py +0 -0
  65. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
  66. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/build_github_performance_corpus.py +0 -0
  67. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/check_ornith_cache.py +0 -0
  68. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/generate_progress_pdf.py +0 -0
  69. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/generate_release_evidence.py +0 -0
  70. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
  71. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/prepare_ornith_cache.py +0 -0
  72. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/run_opencode_lsp_probe.py +0 -0
  73. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/run_openrouter_github_e2e.py +0 -0
  74. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/start_ornith_vllm.sh +0 -0
  75. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/scripts/summarize_opencode_request_payloads.py +0 -0
  76. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/setup.cfg +0 -0
  77. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/corpora.performance.lock.json +0 -0
  78. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
  79. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
  80. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
  81. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/constset.pas +0 -0
  82. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
  83. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
  84. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
  85. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
  86. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
  87. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
  88. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
  89. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
  90. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
  91. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
  92. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
  93. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
  94. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
  95. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
  96. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
  97. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
  98. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
  99. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
  100. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
  101. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
  102. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/properties.pas +0 -0
  103. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
  104. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
  105. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
  106. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
  107. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/library_demo.dpr +0 -0
  108. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/package_demo.dpk +0 -0
  109. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/program_demo.dpr +0 -0
  110. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_advanced.pas +0 -0
  111. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_attributes.pas +0 -0
  112. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_basic.pas +0 -0
  113. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_consumer.pas +0 -0
  114. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_generics.pas +0 -0
  115. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_inheritance.pas +0 -0
  116. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_math.pas +0 -0
  117. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_properties.pas +0 -0
  118. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_sections.pas +0 -0
  119. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_statements.pas +0 -0
  120. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_types.pas +0 -0
  121. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_unresolved.pas +0 -0
  122. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_with.pas +0 -0
  123. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_metrics.py +0 -0
  124. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_protocol.py +0 -0
  125. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_agent_relations.py +0 -0
  126. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_bootstrap_vllm_codebase_skill.py +0 -0
  127. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_bootstrap_vllm_opencode.py +0 -0
  128. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_delphiast_lexer.py +0 -0
  129. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_delphiast_native_compatibility.py +0 -0
  130. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_delphiast_parser.py +0 -0
  131. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_delphiast_semantic_compatibility.py +0 -0
  132. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_diagnostics.py +0 -0
  133. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_github_performance_corpus.py +0 -0
  134. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_language_feature_matrix.py +0 -0
  135. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_legacy_snippets.py +0 -0
  136. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_lsp_features.py +0 -0
  137. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_lsp_support.py +0 -0
  138. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_metrics.py +0 -0
  139. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_navigation_cache.py +0 -0
  140. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_opencode_config.py +0 -0
  141. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_opencode_probe.py +0 -0
  142. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_opencode_request_payloads.py +0 -0
  143. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_openrouter_github_e2e.py +0 -0
  144. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_ornith_cache_prepare.py +0 -0
  145. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_parallel_outline.py +0 -0
  146. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_parser.py +0 -0
  147. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_parser_backends.py +0 -0
  148. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_preprocessor.py +0 -0
  149. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_progress.py +0 -0
  150. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_project_indexer.py +0 -0
  151. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_release_evidence.py +0 -0
  152. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_semantic.py +0 -0
  153. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_vllm_start_script.py +0 -0
  154. {python_delphi_lsp-2.3.1 → python_delphi_lsp-2.3.3}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-delphi-lsp
3
- Version: 2.3.1
3
+ Version: 2.3.3
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
@@ -42,7 +42,7 @@ Dynamic: license-file
42
42
 
43
43
  `python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
44
44
  indexes, serves LSP, and provides bounded codebase navigation for agents.
45
- Version 2.3.1 is authored by Dark Light and supports Windows, macOS, and Linux.
45
+ Version 2.3.3 is authored by Dark Light and supports Windows, macOS, and Linux.
46
46
 
47
47
  ## Install and quick start
48
48
 
@@ -166,7 +166,8 @@ available without returning the complete file as agent context.
166
166
  Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files.
167
167
  Its resolution order is:
168
168
 
169
- 1. An explicit project selection takes precedence.
169
+ 1. An explicit `.dproj`, `.dpr`, or `.dpk` selection takes precedence. An
170
+ explicit `.dproj` resolves its `MainSource`.
170
171
  2. Otherwise, `.dpr` and `.dpk` candidates are considered.
171
172
  3. `MainSource` in a `.dproj` contributes its entry project.
172
173
  4. A selected entry associates same-stem `.dproj`, `.cfg`, and `.dof`.
@@ -175,11 +176,13 @@ Its resolution order is:
175
176
  6. Direct `Unit in 'path/Unit.pas'` references contribute their parent
176
177
  directory to unit search paths.
177
178
 
178
- A single discovered project is selected automatically. With no project entry,
179
- the server uses a synthetic workspace of supported sources. Scans skip build
180
- and cache directories such as `build`, `dist`, environments, VCS folders,
181
- `node_modules`, and tool caches. Missing paths and invalid metadata become
182
- problems; paths are not guessed.
179
+ A single discovered project is selected automatically. With multiple project
180
+ entries, a synthetic repository workspace containing every supported source is
181
+ selected automatically while the concrete projects remain available. With no
182
+ project entry, the same workspace model is used. Scans skip build and cache
183
+ directories such as `build`, `dist`, environments, VCS folders, `node_modules`,
184
+ and tool caches. Missing paths and invalid metadata become problems; paths are
185
+ not guessed.
183
186
 
184
187
  ## Agent CLI and Interface/Protocol v2
185
188
 
@@ -197,7 +200,7 @@ delphi-lsp-agent view --root PATH [--project-file FILE] --layer LAYER
197
200
  delphi-lsp-agent index --root PATH [--project-file FILE] [--out FILE]
198
201
  [--workers auto|N]
199
202
  delphi-lsp-agent query --root PATH ACTION [VALUE]
200
- [--project-id FILE] [--detail summary|declaration|members|context|body|implementations]
203
+ [--project-id ID] [--detail summary|declaration|members|context|body|implementations]
201
204
  [--relation references|callers|callees|uses|used_by|inherits|implements]
202
205
  [--cursor TEXT] [--max-items INT] [--max-chars INT]
203
206
  delphi-lsp-agent skill install [--target PATH] [--force]
@@ -229,6 +232,32 @@ delphi-lsp-agent query --root PATH metrics UNIT_QUERY
229
232
  delphi-lsp-agent cache status --root PATH --format json
230
233
  ```
231
234
 
235
+ The repository root is sufficient even when it contains many projects:
236
+
237
+ ```bash
238
+ delphi-lsp-agent cache start --root PATH
239
+ delphi-lsp-agent query --root PATH find TCustomer
240
+ ```
241
+
242
+ This prewarms one bounded repository navigation index and requires no project
243
+ selection. A `.dproj` is optional. Pass one when its project-specific compiler
244
+ settings and `MainSource` should define the index:
245
+
246
+ ```bash
247
+ delphi-lsp-agent cache start --root PATH --project-file relative/path/Main.dproj
248
+ ```
249
+
250
+ An explicit `.dpr` or `.dpk` remains supported. To switch an already running
251
+ repository cache to one of its concrete project views, list the projects and
252
+ focus one by its returned `project_id`:
253
+
254
+ ```bash
255
+ delphi-lsp-agent query --root PATH open
256
+ delphi-lsp-agent query --root PATH focus --project-id PROJECT_ID
257
+ ```
258
+
259
+ Selecting a project this way also prewarms its navigation cache.
260
+
232
261
  `inspect` uses the currently focused target, so call `focus TARGET_ID` before
233
262
  `inspect` unless a previous request already selected it.
234
263
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  `python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
4
4
  indexes, serves LSP, and provides bounded codebase navigation for agents.
5
- Version 2.3.1 is authored by Dark Light and supports Windows, macOS, and Linux.
5
+ Version 2.3.3 is authored by Dark Light and supports Windows, macOS, and Linux.
6
6
 
7
7
  ## Install and quick start
8
8
 
@@ -126,7 +126,8 @@ available without returning the complete file as agent context.
126
126
  Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files.
127
127
  Its resolution order is:
128
128
 
129
- 1. An explicit project selection takes precedence.
129
+ 1. An explicit `.dproj`, `.dpr`, or `.dpk` selection takes precedence. An
130
+ explicit `.dproj` resolves its `MainSource`.
130
131
  2. Otherwise, `.dpr` and `.dpk` candidates are considered.
131
132
  3. `MainSource` in a `.dproj` contributes its entry project.
132
133
  4. A selected entry associates same-stem `.dproj`, `.cfg`, and `.dof`.
@@ -135,11 +136,13 @@ Its resolution order is:
135
136
  6. Direct `Unit in 'path/Unit.pas'` references contribute their parent
136
137
  directory to unit search paths.
137
138
 
138
- A single discovered project is selected automatically. With no project entry,
139
- the server uses a synthetic workspace of supported sources. Scans skip build
140
- and cache directories such as `build`, `dist`, environments, VCS folders,
141
- `node_modules`, and tool caches. Missing paths and invalid metadata become
142
- problems; paths are not guessed.
139
+ A single discovered project is selected automatically. With multiple project
140
+ entries, a synthetic repository workspace containing every supported source is
141
+ selected automatically while the concrete projects remain available. With no
142
+ project entry, the same workspace model is used. Scans skip build and cache
143
+ directories such as `build`, `dist`, environments, VCS folders, `node_modules`,
144
+ and tool caches. Missing paths and invalid metadata become problems; paths are
145
+ not guessed.
143
146
 
144
147
  ## Agent CLI and Interface/Protocol v2
145
148
 
@@ -157,7 +160,7 @@ delphi-lsp-agent view --root PATH [--project-file FILE] --layer LAYER
157
160
  delphi-lsp-agent index --root PATH [--project-file FILE] [--out FILE]
158
161
  [--workers auto|N]
159
162
  delphi-lsp-agent query --root PATH ACTION [VALUE]
160
- [--project-id FILE] [--detail summary|declaration|members|context|body|implementations]
163
+ [--project-id ID] [--detail summary|declaration|members|context|body|implementations]
161
164
  [--relation references|callers|callees|uses|used_by|inherits|implements]
162
165
  [--cursor TEXT] [--max-items INT] [--max-chars INT]
163
166
  delphi-lsp-agent skill install [--target PATH] [--force]
@@ -189,6 +192,32 @@ delphi-lsp-agent query --root PATH metrics UNIT_QUERY
189
192
  delphi-lsp-agent cache status --root PATH --format json
190
193
  ```
191
194
 
195
+ The repository root is sufficient even when it contains many projects:
196
+
197
+ ```bash
198
+ delphi-lsp-agent cache start --root PATH
199
+ delphi-lsp-agent query --root PATH find TCustomer
200
+ ```
201
+
202
+ This prewarms one bounded repository navigation index and requires no project
203
+ selection. A `.dproj` is optional. Pass one when its project-specific compiler
204
+ settings and `MainSource` should define the index:
205
+
206
+ ```bash
207
+ delphi-lsp-agent cache start --root PATH --project-file relative/path/Main.dproj
208
+ ```
209
+
210
+ An explicit `.dpr` or `.dpk` remains supported. To switch an already running
211
+ repository cache to one of its concrete project views, list the projects and
212
+ focus one by its returned `project_id`:
213
+
214
+ ```bash
215
+ delphi-lsp-agent query --root PATH open
216
+ delphi-lsp-agent query --root PATH focus --project-id PROJECT_ID
217
+ ```
218
+
219
+ Selecting a project this way also prewarms its navigation cache.
220
+
192
221
  `inspect` uses the currently focused target, so call `focus TARGET_ID` before
193
222
  `inspect` unless a previous request already selected it.
194
223
 
@@ -0,0 +1 @@
1
+ __version__ = "2.3.3"
@@ -639,6 +639,21 @@ def _read_startup_tail(diagnostics: object, *, max_bytes: int = _STARTUP_DIAGNOS
639
639
  return b""
640
640
 
641
641
 
642
+ def _daemon_process_options() -> dict[str, object]:
643
+ options: dict[str, object] = {
644
+ "stdin": subprocess.DEVNULL,
645
+ "stdout": subprocess.DEVNULL,
646
+ }
647
+ if os.name == "nt":
648
+ options["creationflags"] = (
649
+ subprocess.CREATE_NO_WINDOW
650
+ | subprocess.CREATE_NEW_PROCESS_GROUP
651
+ )
652
+ else:
653
+ options["start_new_session"] = True
654
+ return options
655
+
656
+
642
657
  class _CacheService:
643
658
  def __init__(self, metadata: CacheMetadata) -> None:
644
659
  self.metadata = metadata
@@ -664,6 +679,7 @@ class _CacheService:
664
679
  self.last_budget = BudgetResult(0, 0.0, 0.0, False, False, False)
665
680
  self.prewarm_seconds = 0.0
666
681
  self.shutdown = threading.Event()
682
+ self.prewarm_thread: threading.Thread | None = None
667
683
 
668
684
  def _measure_retained_bytes(self) -> int:
669
685
  process_rss = current_process_rss_bytes()
@@ -694,15 +710,38 @@ class _CacheService:
694
710
  self.prewarm_seconds = time.monotonic() - started
695
711
  self.stats.parallel_fallbacks = self.context.parallel_stats.fallbacks
696
712
 
713
+ def start_prewarm(self) -> None:
714
+ def run() -> None:
715
+ try:
716
+ with self.lock:
717
+ self.prewarm()
718
+ except Exception:
719
+ self.cache_state = "failed"
720
+
721
+ self.prewarm_thread = threading.Thread(
722
+ target=run,
723
+ name="delphi-cache-prewarm",
724
+ daemon=True,
725
+ )
726
+ self.prewarm_thread.start()
727
+
697
728
  def request(self, request: dict[str, object]) -> CacheClientResponse:
729
+ action = request.get("action")
730
+ if action == "status":
731
+ warning = "" if request.get("_startup_probe") is True else self._consume_warning()
732
+ return CacheClientResponse(self.status(), warning)
733
+ if action == "stop":
734
+ self.shutdown.set()
735
+ return CacheClientResponse({"stopping": True})
736
+ if self.cache_state == "warming":
737
+ self.last_activity = time.monotonic()
738
+ raise CacheClientError(
739
+ "cache_warming",
740
+ "Cache is still warming. Retry after cache status reports ready.",
741
+ )
742
+ if self.cache_state == "failed":
743
+ raise CacheClientError("cache_failed", "Cache warm-up failed.")
698
744
  with self.lock:
699
- action = request.get("action")
700
- if action == "status":
701
- warning = "" if request.get("_startup_probe") is True else self._consume_warning()
702
- return CacheClientResponse(self.status(), warning)
703
- if action == "stop":
704
- self.shutdown.set()
705
- return CacheClientResponse({"stopping": True})
706
745
  self.last_activity = time.monotonic()
707
746
  before = self.last_revision
708
747
  was_warm = self.context.navigation_cache_is_warm
@@ -850,7 +889,7 @@ def run_cache_daemon(
850
889
  watcher: threading.Thread | None = None
851
890
  try:
852
891
  service = _CacheService(metadata)
853
- service.prewarm()
892
+ _write_metadata(metadata)
854
893
  watcher = threading.Thread(
855
894
  target=_watch_workspace,
856
895
  args=(service,),
@@ -858,8 +897,14 @@ def run_cache_daemon(
858
897
  daemon=True,
859
898
  )
860
899
  watcher.start()
861
- _write_metadata(metadata)
862
- while not service.shutdown.is_set() and time.monotonic() - service.last_activity < idle_timeout:
900
+ service.start_prewarm()
901
+ while (
902
+ not service.shutdown.is_set()
903
+ and (
904
+ service.cache_state == "warming"
905
+ or time.monotonic() - service.last_activity < idle_timeout
906
+ )
907
+ ):
863
908
  try:
864
909
  connection, _ = listener.accept()
865
910
  except socket.timeout:
@@ -921,11 +966,7 @@ def _start_cache_unlocked(
921
966
  ]
922
967
  if project:
923
968
  command.extend(("--project-file", project))
924
- options: dict[str, object] = {"stdin": subprocess.DEVNULL, "stdout": subprocess.DEVNULL}
925
- if os.name == "nt":
926
- options["creationflags"] = subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP
927
- else:
928
- options["start_new_session"] = True
969
+ options = _daemon_process_options()
929
970
  with tempfile.TemporaryFile() as diagnostics:
930
971
  options["stderr"] = diagnostics
931
972
  process = subprocess.Popen(command, **options)
@@ -1000,7 +1041,13 @@ def query_cache(root: str | Path, request: dict[str, object]) -> CacheClientResp
1000
1041
  if not _pid_alive(metadata.pid):
1001
1042
  _remove_metadata_if_owned(metadata)
1002
1043
  raise CacheClientError("cache_not_running", "Cache daemon is not running.")
1003
- return _client_exchange(metadata, request)
1044
+ while True:
1045
+ try:
1046
+ return _client_exchange(metadata, request)
1047
+ except CacheClientError as error:
1048
+ if error.code != "cache_warming":
1049
+ raise
1050
+ time.sleep(0.05)
1004
1051
 
1005
1052
 
1006
1053
  def cache_status(root: str | Path) -> dict[str, object]:
@@ -151,7 +151,14 @@ def build_parser() -> argparse.ArgumentParser:
151
151
 
152
152
  def _add_cache_start_arguments(parser: argparse.ArgumentParser) -> None:
153
153
  parser.add_argument("--root", type=Path, default=Path("."))
154
- parser.add_argument("--project-file", type=Path)
154
+ parser.add_argument(
155
+ "--project-file",
156
+ type=Path,
157
+ help=(
158
+ "Optionally select a .dproj, .dpr, or .dpk file, relative to "
159
+ "--root if needed."
160
+ ),
161
+ )
155
162
  parser.add_argument("--max-memory", type=parse_memory_size, default=DEFAULT_MAX_MEMORY_BYTES)
156
163
  parser.add_argument("--workers", type=parse_worker_setting, default=0)
157
164
  parser.add_argument("--idle-timeout", type=_positive_integer, default=DEFAULT_IDLE_TIMEOUT)
@@ -853,6 +853,7 @@ class AgentContext:
853
853
  )
854
854
  elif request.project_id:
855
855
  self._focus = Focus(project_id=self._workspace.active_project_id)
856
+ self._require_registry(revision)
856
857
  return self._response(request, revision, [self._focus.to_mapping()])
857
858
 
858
859
  def _handle_metrics(self, request: AgentRequest, revision: str) -> AgentResponse:
@@ -992,7 +993,8 @@ class AgentContext:
992
993
  if not project_id:
993
994
  raise AgentProtocolError(
994
995
  "project_required",
995
- "Select a project before querying symbols.",
996
+ "Multiple projects were found. Run 'query open', then select one "
997
+ "with 'query focus --project-id PROJECT_ID'.",
996
998
  )
997
999
  return project_id
998
1000
 
@@ -220,7 +220,7 @@ Inspect Delphi/Object Pascal only through `delphi_codebase`; never raw bash/read
220
220
 
221
221
  ## Protocol v2 workflow
222
222
 
223
- 1. Call `open`. If the requested project is not active, select it with `focus(project_id)`.
223
+ 1. Call `open`. A multi-project repository is active as one workspace by default; select a concrete project with `focus(project_id)` only when project-specific compiler context is needed.
224
224
  2. Call `find` with a narrow query, then `focus(target_id)` for the returned target.
225
225
  3. Inspect focused details in this order as needed: `summary`, `declaration`, `members`, `context`, `body`, `implementations`.
226
226
  4. Trace relations with `references`, `callers`, `callees`, `uses`, `used_by`, `inherits`, or `implements`.
@@ -112,6 +112,21 @@ class AgentWorkspace:
112
112
  )
113
113
  projects: list[AgentProject] = []
114
114
  project_paths: dict[str, Path | None] = {}
115
+ default_project_id = ""
116
+ if (
117
+ resolved_project_file is None
118
+ and len(discovery.project_files) > 1
119
+ ):
120
+ default_project_id = make_target_id("project", "", "workspace")
121
+ projects.append(
122
+ AgentProject(
123
+ project_id=default_project_id,
124
+ name="Workspace",
125
+ path=".",
126
+ kind="workspace",
127
+ )
128
+ )
129
+ project_paths[default_project_id] = None
115
130
  if discovery.project_files:
116
131
  for value in discovery.project_files:
117
132
  path = Path(value)
@@ -140,7 +155,9 @@ class AgentWorkspace:
140
155
  project_paths[project_id] = None
141
156
 
142
157
  workspace = cls(root_path, discovery, tuple(projects), project_paths)
143
- if len(projects) == 1:
158
+ if default_project_id:
159
+ workspace.select_project(default_project_id)
160
+ elif len(projects) == 1:
144
161
  workspace.select_project(projects[0].project_id)
145
162
  return workspace
146
163
 
@@ -305,7 +322,11 @@ class AgentWorkspace:
305
322
  project_path = self._project_paths[project_id]
306
323
  cached = self._project_cache.get(project_id)
307
324
  if project_path is None:
308
- discovery = self._discovery if cached is None else discover_workspace_sources(self._root)
325
+ discovery = (
326
+ self._discovery
327
+ if cached is None and self._discovery.source_files
328
+ else discover_workspace_sources(self._root)
329
+ )
309
330
  else:
310
331
  discovery = discover_delphi_project(
311
332
  self._root,
@@ -146,7 +146,21 @@ def discover_delphi_project(
146
146
  for value in defines:
147
147
  add_define(value)
148
148
 
149
- candidates = _project_candidates(root_path, project_path)
149
+ explicit_dproj: Path | None = None
150
+ if (
151
+ project_path is not None
152
+ and project_path.suffix.casefold() == ".dproj"
153
+ ):
154
+ explicit_dproj = project_path
155
+ project_path = _project_entry_from_dproj(
156
+ explicit_dproj,
157
+ discovery,
158
+ )
159
+ candidates = (
160
+ []
161
+ if explicit_dproj is not None and project_path is None
162
+ else _project_candidates(root_path, project_path)
163
+ )
150
164
  for project in candidates:
151
165
  key = str(project).casefold()
152
166
  if key not in seen_projects:
@@ -160,8 +174,13 @@ def discover_delphi_project(
160
174
  seen_search,
161
175
  discovery.search_path_origins,
162
176
  )
163
- dproj = project.with_suffix(".dproj")
164
- if dproj.exists():
177
+ dproj_candidates = [project.with_suffix(".dproj")]
178
+ if explicit_dproj is not None:
179
+ dproj_candidates.insert(0, explicit_dproj)
180
+ for dproj in dproj_candidates:
181
+ config_key = str(dproj).casefold()
182
+ if config_key in seen_configs or not dproj.exists():
183
+ continue
165
184
  _read_dproj(
166
185
  dproj,
167
186
  discovery,
@@ -173,7 +192,7 @@ def discover_delphi_project(
173
192
  discovery.include_path_origins,
174
193
  add_define,
175
194
  )
176
- seen_configs.add(str(dproj).casefold())
195
+ seen_configs.add(config_key)
177
196
  discovery.config_files.append(str(dproj))
178
197
  for cfg in (project.with_suffix(".cfg"), project.with_suffix(".dof")):
179
198
  if cfg.exists():
@@ -483,6 +502,72 @@ def _main_source_from_dproj(path: Path) -> str | None:
483
502
  return None
484
503
 
485
504
 
505
+ def _project_entry_from_dproj(
506
+ path: Path,
507
+ discovery: DelphiProjectDiscovery,
508
+ ) -> Path | None:
509
+ try:
510
+ root = ET.parse(path).getroot()
511
+ except ET.ParseError as exc:
512
+ discovery.problems.append(
513
+ DiscoveryProblem(
514
+ "cant_read_project",
515
+ f"Could not parse Delphi project file: {exc}",
516
+ str(path),
517
+ )
518
+ )
519
+ return None
520
+ except OSError as exc:
521
+ discovery.problems.append(
522
+ DiscoveryProblem(
523
+ "cant_read_project",
524
+ f"Could not read Delphi project file: {exc}",
525
+ str(path),
526
+ )
527
+ )
528
+ return None
529
+
530
+ main_source = next(
531
+ (
532
+ (element.text or "").strip()
533
+ for element in root.iter()
534
+ if _xml_local_name(element.tag) == "MainSource"
535
+ and (element.text or "").strip()
536
+ ),
537
+ "",
538
+ )
539
+ if not main_source:
540
+ discovery.problems.append(
541
+ DiscoveryProblem(
542
+ "cant_read_project",
543
+ "Delphi project file does not define MainSource.",
544
+ str(path),
545
+ )
546
+ )
547
+ return None
548
+
549
+ entry = (path.parent / main_source).resolve()
550
+ if entry.suffix.casefold() not in PROJECT_EXTENSIONS:
551
+ discovery.problems.append(
552
+ DiscoveryProblem(
553
+ "cant_read_project",
554
+ "MainSource must reference a .dpr or .dpk entry file.",
555
+ str(path),
556
+ )
557
+ )
558
+ return None
559
+ if not entry.is_file():
560
+ discovery.problems.append(
561
+ DiscoveryProblem(
562
+ "cant_read_project",
563
+ f"MainSource does not exist: {entry}",
564
+ str(path),
565
+ )
566
+ )
567
+ return None
568
+ return entry
569
+
570
+
486
571
  def _scan_sources(
487
572
  root: Path,
488
573
  discovery: DelphiProjectDiscovery,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-delphi-lsp"
7
- version = "2.3.1"
7
+ version = "2.3.3"
8
8
  description = "Python Delphi/Object Pascal parser, semantic indexer, and language server."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-delphi-lsp
3
- Version: 2.3.1
3
+ Version: 2.3.3
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
@@ -42,7 +42,7 @@ Dynamic: license-file
42
42
 
43
43
  `python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
44
44
  indexes, serves LSP, and provides bounded codebase navigation for agents.
45
- Version 2.3.1 is authored by Dark Light and supports Windows, macOS, and Linux.
45
+ Version 2.3.3 is authored by Dark Light and supports Windows, macOS, and Linux.
46
46
 
47
47
  ## Install and quick start
48
48
 
@@ -166,7 +166,8 @@ available without returning the complete file as agent context.
166
166
  Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files.
167
167
  Its resolution order is:
168
168
 
169
- 1. An explicit project selection takes precedence.
169
+ 1. An explicit `.dproj`, `.dpr`, or `.dpk` selection takes precedence. An
170
+ explicit `.dproj` resolves its `MainSource`.
170
171
  2. Otherwise, `.dpr` and `.dpk` candidates are considered.
171
172
  3. `MainSource` in a `.dproj` contributes its entry project.
172
173
  4. A selected entry associates same-stem `.dproj`, `.cfg`, and `.dof`.
@@ -175,11 +176,13 @@ Its resolution order is:
175
176
  6. Direct `Unit in 'path/Unit.pas'` references contribute their parent
176
177
  directory to unit search paths.
177
178
 
178
- A single discovered project is selected automatically. With no project entry,
179
- the server uses a synthetic workspace of supported sources. Scans skip build
180
- and cache directories such as `build`, `dist`, environments, VCS folders,
181
- `node_modules`, and tool caches. Missing paths and invalid metadata become
182
- problems; paths are not guessed.
179
+ A single discovered project is selected automatically. With multiple project
180
+ entries, a synthetic repository workspace containing every supported source is
181
+ selected automatically while the concrete projects remain available. With no
182
+ project entry, the same workspace model is used. Scans skip build and cache
183
+ directories such as `build`, `dist`, environments, VCS folders, `node_modules`,
184
+ and tool caches. Missing paths and invalid metadata become problems; paths are
185
+ not guessed.
183
186
 
184
187
  ## Agent CLI and Interface/Protocol v2
185
188
 
@@ -197,7 +200,7 @@ delphi-lsp-agent view --root PATH [--project-file FILE] --layer LAYER
197
200
  delphi-lsp-agent index --root PATH [--project-file FILE] [--out FILE]
198
201
  [--workers auto|N]
199
202
  delphi-lsp-agent query --root PATH ACTION [VALUE]
200
- [--project-id FILE] [--detail summary|declaration|members|context|body|implementations]
203
+ [--project-id ID] [--detail summary|declaration|members|context|body|implementations]
201
204
  [--relation references|callers|callees|uses|used_by|inherits|implements]
202
205
  [--cursor TEXT] [--max-items INT] [--max-chars INT]
203
206
  delphi-lsp-agent skill install [--target PATH] [--force]
@@ -229,6 +232,32 @@ delphi-lsp-agent query --root PATH metrics UNIT_QUERY
229
232
  delphi-lsp-agent cache status --root PATH --format json
230
233
  ```
231
234
 
235
+ The repository root is sufficient even when it contains many projects:
236
+
237
+ ```bash
238
+ delphi-lsp-agent cache start --root PATH
239
+ delphi-lsp-agent query --root PATH find TCustomer
240
+ ```
241
+
242
+ This prewarms one bounded repository navigation index and requires no project
243
+ selection. A `.dproj` is optional. Pass one when its project-specific compiler
244
+ settings and `MainSource` should define the index:
245
+
246
+ ```bash
247
+ delphi-lsp-agent cache start --root PATH --project-file relative/path/Main.dproj
248
+ ```
249
+
250
+ An explicit `.dpr` or `.dpk` remains supported. To switch an already running
251
+ repository cache to one of its concrete project views, list the projects and
252
+ focus one by its returned `project_id`:
253
+
254
+ ```bash
255
+ delphi-lsp-agent query --root PATH open
256
+ delphi-lsp-agent query --root PATH focus --project-id PROJECT_ID
257
+ ```
258
+
259
+ Selecting a project this way also prewarms its navigation cache.
260
+
232
261
  `inspect` uses the currently focused target, so call `focus TARGET_ID` before
233
262
  `inspect` unless a previous request already selected it.
234
263