python-delphi-lsp 2.3.2__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.2/python_delphi_lsp.egg-info → python_delphi_lsp-2.3.3}/PKG-INFO +2 -2
  2. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/README.md +1 -1
  3. python_delphi_lsp-2.3.3/delphi_lsp/_version.py +1 -0
  4. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_cache.py +47 -11
  5. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/pyproject.toml +1 -1
  6. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3/python_delphi_lsp.egg-info}/PKG-INFO +2 -2
  7. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_cache.py +98 -0
  8. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_package_metadata.py +3 -3
  9. python_delphi_lsp-2.3.2/delphi_lsp/_version.py +0 -1
  10. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/.github/workflows/ci.yml +0 -0
  11. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/LICENSE +0 -0
  12. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/MANIFEST.in +0 -0
  13. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/__init__.py +0 -0
  14. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_cli.py +0 -0
  15. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_context.py +0 -0
  16. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_layers.py +0 -0
  17. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_metrics.py +0 -0
  18. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_protocol.py +0 -0
  19. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_relations.py +0 -0
  20. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_templates.py +0 -0
  21. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/agent_workspace.py +0 -0
  22. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/binary.py +0 -0
  23. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/comment_builder.py +0 -0
  24. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/consts.py +0 -0
  25. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/delphiast_lexer.py +0 -0
  26. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/delphiast_parser.py +0 -0
  27. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/delphiast_tokens.py +0 -0
  28. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/grammar.py +0 -0
  29. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/lark_builder.py +0 -0
  30. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/lark_tokens.py +0 -0
  31. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/lsp_server.py +0 -0
  32. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/metrics.py +0 -0
  33. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/navigation_cache.py +0 -0
  34. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/nodes.py +0 -0
  35. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/parallel_outline.py +0 -0
  36. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/parser.py +0 -0
  37. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/parser_backend.py +0 -0
  38. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/preprocessor.py +0 -0
  39. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/progress.py +0 -0
  40. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/project_discovery.py +0 -0
  41. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/project_indexer.py +0 -0
  42. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/semantic.py +0 -0
  43. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/semantic_builder.py +0 -0
  44. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/source_reader.py +0 -0
  45. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/workspace.py +0 -0
  46. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/delphi_lsp/writer.py +0 -0
  47. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/opencode.json +0 -0
  48. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/SOURCES.txt +0 -0
  49. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
  50. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/entry_points.txt +0 -0
  51. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/requires.txt +0 -0
  52. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/python_delphi_lsp.egg-info/top_level.txt +0 -0
  53. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/audit_delphi_language_features.py +0 -0
  54. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/benchmark_github_corpus.py +0 -0
  55. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/benchmark_parallel_cache.py +0 -0
  56. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_codebase_skill_test.py +0 -0
  57. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
  58. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_opencode_test.py +0 -0
  59. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
  60. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/build_github_performance_corpus.py +0 -0
  61. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/check_ornith_cache.py +0 -0
  62. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/generate_progress_pdf.py +0 -0
  63. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/generate_release_evidence.py +0 -0
  64. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
  65. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/prepare_ornith_cache.py +0 -0
  66. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/run_opencode_lsp_probe.py +0 -0
  67. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/run_openrouter_github_e2e.py +0 -0
  68. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/start_ornith_vllm.sh +0 -0
  69. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/scripts/summarize_opencode_request_payloads.py +0 -0
  70. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/setup.cfg +0 -0
  71. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/corpora.performance.lock.json +0 -0
  72. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
  73. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
  74. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
  75. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/constset.pas +0 -0
  76. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
  77. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
  78. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
  79. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
  80. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
  81. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
  82. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
  83. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
  84. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
  85. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
  86. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
  87. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
  88. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
  89. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
  90. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
  91. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
  92. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
  93. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
  94. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
  95. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
  96. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/properties.pas +0 -0
  97. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
  98. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
  99. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
  100. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
  101. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/library_demo.dpr +0 -0
  102. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/package_demo.dpk +0 -0
  103. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/program_demo.dpr +0 -0
  104. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_advanced.pas +0 -0
  105. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_attributes.pas +0 -0
  106. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_basic.pas +0 -0
  107. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_consumer.pas +0 -0
  108. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_generics.pas +0 -0
  109. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_inheritance.pas +0 -0
  110. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_math.pas +0 -0
  111. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_properties.pas +0 -0
  112. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_sections.pas +0 -0
  113. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_statements.pas +0 -0
  114. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_types.pas +0 -0
  115. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_unresolved.pas +0 -0
  116. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/fixtures/unit_with.pas +0 -0
  117. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_cli_errors.py +0 -0
  118. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_codebase.py +0 -0
  119. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_context.py +0 -0
  120. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_metrics.py +0 -0
  121. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_protocol.py +0 -0
  122. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_relations.py +0 -0
  123. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_worker.py +0 -0
  124. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_agent_workspace.py +0 -0
  125. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_bootstrap_vllm_codebase_skill.py +0 -0
  126. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_bootstrap_vllm_opencode.py +0 -0
  127. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_delphiast_lexer.py +0 -0
  128. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_delphiast_native_compatibility.py +0 -0
  129. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_delphiast_parser.py +0 -0
  130. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_delphiast_semantic_compatibility.py +0 -0
  131. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_diagnostics.py +0 -0
  132. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_github_performance_corpus.py +0 -0
  133. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_language_feature_matrix.py +0 -0
  134. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_legacy_snippets.py +0 -0
  135. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_lsp_features.py +0 -0
  136. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_lsp_support.py +0 -0
  137. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_metrics.py +0 -0
  138. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_navigation_cache.py +0 -0
  139. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_opencode_config.py +0 -0
  140. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_opencode_probe.py +0 -0
  141. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_opencode_request_payloads.py +0 -0
  142. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_openrouter_github_e2e.py +0 -0
  143. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_ornith_cache_prepare.py +0 -0
  144. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_parallel_outline.py +0 -0
  145. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_parser.py +0 -0
  146. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_parser_backends.py +0 -0
  147. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_preprocessor.py +0 -0
  148. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_progress.py +0 -0
  149. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_project_discovery.py +0 -0
  150. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_project_indexer.py +0 -0
  151. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_release_evidence.py +0 -0
  152. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_semantic.py +0 -0
  153. {python_delphi_lsp-2.3.2 → python_delphi_lsp-2.3.3}/tests/test_vllm_start_script.py +0 -0
  154. {python_delphi_lsp-2.3.2 → 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.2
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.2 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
 
@@ -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.2 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
 
@@ -0,0 +1 @@
1
+ __version__ = "2.3.3"
@@ -679,6 +679,7 @@ class _CacheService:
679
679
  self.last_budget = BudgetResult(0, 0.0, 0.0, False, False, False)
680
680
  self.prewarm_seconds = 0.0
681
681
  self.shutdown = threading.Event()
682
+ self.prewarm_thread: threading.Thread | None = None
682
683
 
683
684
  def _measure_retained_bytes(self) -> int:
684
685
  process_rss = current_process_rss_bytes()
@@ -709,15 +710,38 @@ class _CacheService:
709
710
  self.prewarm_seconds = time.monotonic() - started
710
711
  self.stats.parallel_fallbacks = self.context.parallel_stats.fallbacks
711
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
+
712
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.")
713
744
  with self.lock:
714
- action = request.get("action")
715
- if action == "status":
716
- warning = "" if request.get("_startup_probe") is True else self._consume_warning()
717
- return CacheClientResponse(self.status(), warning)
718
- if action == "stop":
719
- self.shutdown.set()
720
- return CacheClientResponse({"stopping": True})
721
745
  self.last_activity = time.monotonic()
722
746
  before = self.last_revision
723
747
  was_warm = self.context.navigation_cache_is_warm
@@ -865,7 +889,7 @@ def run_cache_daemon(
865
889
  watcher: threading.Thread | None = None
866
890
  try:
867
891
  service = _CacheService(metadata)
868
- service.prewarm()
892
+ _write_metadata(metadata)
869
893
  watcher = threading.Thread(
870
894
  target=_watch_workspace,
871
895
  args=(service,),
@@ -873,8 +897,14 @@ def run_cache_daemon(
873
897
  daemon=True,
874
898
  )
875
899
  watcher.start()
876
- _write_metadata(metadata)
877
- 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
+ ):
878
908
  try:
879
909
  connection, _ = listener.accept()
880
910
  except socket.timeout:
@@ -1011,7 +1041,13 @@ def query_cache(root: str | Path, request: dict[str, object]) -> CacheClientResp
1011
1041
  if not _pid_alive(metadata.pid):
1012
1042
  _remove_metadata_if_owned(metadata)
1013
1043
  raise CacheClientError("cache_not_running", "Cache daemon is not running.")
1014
- 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)
1015
1051
 
1016
1052
 
1017
1053
  def cache_status(root: str | Path) -> dict[str, object]:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-delphi-lsp"
7
- version = "2.3.2"
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.2
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.2 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
 
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from collections.abc import Iterator, Mapping
4
+ import contextlib
4
5
  from dataclasses import dataclass
5
6
  import json
6
7
  import os
@@ -149,6 +150,103 @@ def test_cache_daemon_lifecycle_reuses_one_authenticated_process(tmp_path: Path)
149
150
  stop_cache(tmp_path)
150
151
 
151
152
 
153
+ def test_cache_daemon_reports_ready_before_slow_prewarm_finishes(
154
+ tmp_path: Path,
155
+ monkeypatch: pytest.MonkeyPatch,
156
+ ) -> None:
157
+ from delphi_lsp import agent_cache
158
+
159
+ write_source(tmp_path / "Demo.dpr", "program Demo; begin end.")
160
+ prewarm_started = threading.Event()
161
+ allow_prewarm = threading.Event()
162
+ real_prewarm = agent_cache._CacheService.prewarm
163
+
164
+ def slow_prewarm(service: agent_cache._CacheService) -> None:
165
+ prewarm_started.set()
166
+ assert allow_prewarm.wait(timeout=5)
167
+ real_prewarm(service)
168
+
169
+ monkeypatch.setattr(agent_cache._CacheService, "prewarm", slow_prewarm)
170
+ daemon = threading.Thread(
171
+ target=agent_cache.run_cache_daemon,
172
+ args=(tmp_path,),
173
+ kwargs={"idle_timeout": 10},
174
+ daemon=True,
175
+ )
176
+ daemon.start()
177
+
178
+ try:
179
+ assert prewarm_started.wait(timeout=2)
180
+ deadline = time.monotonic() + 2
181
+ metadata = agent_cache._read_metadata(tmp_path)
182
+ while metadata is None and time.monotonic() < deadline:
183
+ time.sleep(0.01)
184
+ metadata = agent_cache._read_metadata(tmp_path)
185
+
186
+ assert metadata is not None
187
+ status = agent_cache._client_exchange(
188
+ metadata,
189
+ {"action": "status", "_startup_probe": True},
190
+ ).payload
191
+ assert status["cache_state"] == "warming"
192
+ finally:
193
+ allow_prewarm.set()
194
+ deadline = time.monotonic() + 2
195
+ metadata = agent_cache._read_metadata(tmp_path)
196
+ while metadata is None and time.monotonic() < deadline:
197
+ time.sleep(0.01)
198
+ metadata = agent_cache._read_metadata(tmp_path)
199
+ if metadata is not None:
200
+ with contextlib.suppress(agent_cache.CacheClientError):
201
+ agent_cache._client_exchange(metadata, {"action": "stop"})
202
+ daemon.join(timeout=3)
203
+
204
+
205
+ def test_query_cache_retries_while_daemon_is_warming(
206
+ tmp_path: Path,
207
+ monkeypatch: pytest.MonkeyPatch,
208
+ ) -> None:
209
+ from delphi_lsp import agent_cache
210
+
211
+ metadata = agent_cache.CacheMetadata(
212
+ 2,
213
+ str(tmp_path.resolve()),
214
+ os.getpid(),
215
+ 1,
216
+ "x" * 32,
217
+ "test",
218
+ "",
219
+ 512 * 1024**2,
220
+ 0,
221
+ 10,
222
+ time.time(),
223
+ )
224
+ attempts = 0
225
+
226
+ def exchange(
227
+ _metadata: agent_cache.CacheMetadata,
228
+ _request: dict[str, object],
229
+ ) -> agent_cache.CacheClientResponse:
230
+ nonlocal attempts
231
+ attempts += 1
232
+ if attempts == 1:
233
+ raise agent_cache.CacheClientError(
234
+ "cache_warming",
235
+ "Cache is still warming.",
236
+ )
237
+ return agent_cache.CacheClientResponse({"schema": 2})
238
+
239
+ monkeypatch.setattr(agent_cache, "_read_metadata", lambda _root: metadata)
240
+ monkeypatch.setattr(agent_cache, "_pid_alive", lambda _pid: True)
241
+ monkeypatch.setattr(agent_cache, "_client_exchange", exchange)
242
+ monkeypatch.setattr(agent_cache.time, "sleep", lambda _seconds: None)
243
+
244
+ response = agent_cache.query_cache(tmp_path, {"action": "open"})
245
+
246
+ assert response.payload == {"schema": 2}
247
+ assert attempts == 2
248
+
249
+
152
250
  def test_cache_daemon_compacts_handles_bad_clients_and_idles(tmp_path: Path) -> None:
153
251
  from delphi_lsp.agent_cache import cache_metadata_path, cache_status, query_cache, start_cache, stop_cache
154
252
 
@@ -28,12 +28,12 @@ def test_lsp_console_script_dependencies_are_installed_by_default() -> None:
28
28
  assert '"lsprotocol>=2023.0.1"' in project
29
29
 
30
30
 
31
- def test_release_metadata_declares_2_3_2_sole_namespace_author_and_windows_support() -> None:
31
+ def test_release_metadata_declares_2_3_3_sole_namespace_author_and_windows_support() -> None:
32
32
  pyproject = (ROOT / 'pyproject.toml').read_text(encoding='utf-8')
33
33
  project = _section('project', pyproject)
34
34
  scripts = _section('project.scripts', pyproject)
35
35
 
36
- assert 'version = "2.3.2"' in project
36
+ assert 'version = "2.3.3"' in project
37
37
  assert '"Operating System :: OS Independent"' in project
38
38
  assert '"Operating System :: Microsoft :: Windows"' in project
39
39
  assert '"Operating System :: MacOS"' in project
@@ -83,7 +83,7 @@ def test_readme_documents_v2_release_plugin_protocol_discovery_and_vllm_proof()
83
83
  assert 'Auto-discovery reads `.dpr`, `.dpk`, `.dproj`, `.cfg`, and `.dof` files' in readme
84
84
  assert 'no file-size threshold' in readme
85
85
  assert 'final answer' in readme
86
- assert 'Version 2.3.2' in readme
86
+ assert 'Version 2.3.3' in readme
87
87
  assert 'view --layer metrics' in readme
88
88
  assert '`metrics`' in readme
89
89
  assert 'total_loc_with_includes' in readme
@@ -1 +0,0 @@
1
- __version__ = "2.3.2"