python-delphi-lsp 2.1.0__tar.gz → 2.2.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.
- {python_delphi_lsp-2.1.0/python_delphi_lsp.egg-info → python_delphi_lsp-2.2.0}/PKG-INFO +21 -11
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/README.md +19 -10
- python_delphi_lsp-2.2.0/delphi_lsp/_version.py +1 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_cache.py +46 -6
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_context.py +323 -33
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_relations.py +28 -3
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_workspace.py +35 -0
- python_delphi_lsp-2.2.0/delphi_lsp/delphiast_lexer.py +284 -0
- python_delphi_lsp-2.2.0/delphi_lsp/delphiast_parser.py +1498 -0
- python_delphi_lsp-2.2.0/delphi_lsp/delphiast_tokens.py +41 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/metrics.py +35 -1
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/parallel_outline.py +49 -10
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/parser.py +54 -4
- python_delphi_lsp-2.2.0/delphi_lsp/parser_backend.py +57 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/project_indexer.py +32 -1
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/pyproject.toml +2 -1
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0/python_delphi_lsp.egg-info}/PKG-INFO +21 -11
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/python_delphi_lsp.egg-info/SOURCES.txt +9 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/python_delphi_lsp.egg-info/requires.txt +1 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_cache.py +104 -6
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_context.py +137 -1
- python_delphi_lsp-2.2.0/tests/test_delphiast_lexer.py +97 -0
- python_delphi_lsp-2.2.0/tests/test_delphiast_native_compatibility.py +364 -0
- python_delphi_lsp-2.2.0/tests/test_delphiast_parser.py +121 -0
- python_delphi_lsp-2.2.0/tests/test_delphiast_semantic_compatibility.py +74 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_package_metadata.py +3 -3
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_parallel_outline.py +31 -3
- python_delphi_lsp-2.2.0/tests/test_parser_backends.py +135 -0
- python_delphi_lsp-2.1.0/delphi_lsp/_version.py +0 -1
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/.github/workflows/ci.yml +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/LICENSE +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/MANIFEST.in +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/__init__.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_cli.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_layers.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_metrics.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_protocol.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/agent_templates.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/binary.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/comment_builder.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/consts.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/grammar.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/lark_builder.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/lark_tokens.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/lsp_server.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/nodes.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/preprocessor.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/progress.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/project_discovery.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/semantic.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/semantic_builder.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/source_reader.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/workspace.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/delphi_lsp/writer.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/opencode.json +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/python_delphi_lsp.egg-info/dependency_links.txt +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/python_delphi_lsp.egg-info/entry_points.txt +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/python_delphi_lsp.egg-info/top_level.txt +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/audit_delphi_language_features.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/benchmark_github_corpus.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/benchmark_parallel_cache.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/bootstrap_vllm_codebase_skill_test.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/bootstrap_vllm_opencode_test.ps1 +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/bootstrap_vllm_opencode_test.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/bootstrap_vllm_opencode_test.sh +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/build_github_performance_corpus.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/check_ornith_cache.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/generate_progress_pdf.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/generate_release_evidence.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/ollama/ornith-lspctx.Modelfile +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/prepare_ornith_cache.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/run_opencode_lsp_probe.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/run_openrouter_github_e2e.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/start_ornith_vllm.sh +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/scripts/summarize_opencode_request_payloads.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/setup.cfg +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/corpora.performance.lock.json +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/DeprecatedOnConst.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/VariantRecordFieldAttributes.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/alignedrecords.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/constset.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/deprecatedtype.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/dottedtypes.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/endtoken.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/experimentals.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/externalfunction.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/finalizationinitializationexports.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/forwardoverloaded.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/forwardwithoutsemicolon.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/genericconstraints.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/genericinterfacemethoddelegation.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/implementsgenerictype.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/include file2.inc +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/includefile.inc +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/includefile.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/managedrecords.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/messagemethod.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/multiline.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/nonalignedrecords.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/numbers.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/pointerchars.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/properties.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/strictvisibility.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/tryexcept.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/umlauts.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/legacy_snippets/whitespacearoundifdefcondition.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/library_demo.dpr +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/package_demo.dpk +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/program_demo.dpr +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_advanced.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_attributes.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_basic.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_consumer.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_generics.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_inheritance.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_math.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_properties.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_sections.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_statements.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_types.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_unresolved.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/fixtures/unit_with.pas +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_codebase.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_metrics.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_protocol.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_relations.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_worker.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_agent_workspace.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_bootstrap_vllm_codebase_skill.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_bootstrap_vllm_opencode.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_diagnostics.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_github_performance_corpus.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_language_feature_matrix.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_legacy_snippets.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_lsp_features.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_lsp_support.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_metrics.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_opencode_config.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_opencode_probe.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_opencode_request_payloads.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_openrouter_github_e2e.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_ornith_cache_prepare.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_parser.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_preprocessor.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_progress.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_project_discovery.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_project_indexer.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_release_evidence.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_semantic.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/tests/test_vllm_start_script.py +0 -0
- {python_delphi_lsp-2.1.0 → python_delphi_lsp-2.2.0}/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
|
+
Version: 2.2.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
|
|
@@ -24,6 +24,7 @@ License-File: LICENSE
|
|
|
24
24
|
Requires-Dist: lark>=1.1.9
|
|
25
25
|
Requires-Dist: pygls<2.0,>=1.3.0
|
|
26
26
|
Requires-Dist: lsprotocol>=2023.0.1
|
|
27
|
+
Requires-Dist: watchfiles<2.0,>=1.2
|
|
27
28
|
Provides-Extra: lsp
|
|
28
29
|
Requires-Dist: pygls<2.0,>=1.3.0; extra == "lsp"
|
|
29
30
|
Requires-Dist: lsprotocol>=2023.0.1; extra == "lsp"
|
|
@@ -41,7 +42,7 @@ Dynamic: license-file
|
|
|
41
42
|
|
|
42
43
|
`python-delphi-lsp` parses Delphi/Object Pascal, builds semantic and project
|
|
43
44
|
indexes, serves LSP, and provides bounded codebase navigation for agents.
|
|
44
|
-
Version 2.
|
|
45
|
+
Version 2.2.0 is authored by Dark Light and supports Windows, macOS, and Linux.
|
|
45
46
|
|
|
46
47
|
## Install and quick start
|
|
47
48
|
|
|
@@ -238,19 +239,28 @@ above 80 percent.
|
|
|
238
239
|
|
|
239
240
|
Cold builds parse independent source units in short-lived processes created with
|
|
240
241
|
the cross-platform `spawn` method. `--workers auto|N` defaults to `auto`.
|
|
241
|
-
Automatic selection uses at most
|
|
242
|
+
Automatic selection uses at most eight worker processes, leaves one detected CPU
|
|
242
243
|
free, never exceeds the source task count, and—for the cache daemon—allows one
|
|
243
|
-
worker per `
|
|
244
|
-
task, CPU, and
|
|
244
|
+
worker per `64 MiB` of retained-cache budget. `view` and `index` use the same
|
|
245
|
+
task, CPU, and eight-worker caps without the cache-budget term. An explicit value
|
|
245
246
|
from 1 through 32 overrides the automatic CPU and memory caps but is still
|
|
246
247
|
limited by the number of tasks.
|
|
247
248
|
|
|
248
|
-
Worker processes
|
|
249
|
-
|
|
250
|
-
the
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
Worker processes build compact, detached navigation shards and exit before
|
|
250
|
+
retained-cache accounting. Full semantic object graphs and source text are not
|
|
251
|
+
retained in the parent. Tokenized source documents are loaded only for source
|
|
252
|
+
evidence requests such as `inspect`, and a byte-bounded LRU evicts older
|
|
253
|
+
documents. The transient worker memory remains separate from retained navigation
|
|
254
|
+
structures and the existing 80-percent warning. Retained bytes are maintained
|
|
255
|
+
incrementally; requests never traverse the complete cache object graph merely
|
|
256
|
+
to measure it. If an automatic pool fails before accepting a result, one
|
|
257
|
+
automatic serial fallback is attempted; explicit worker counts fail instead of
|
|
258
|
+
silently changing the requested configuration.
|
|
259
|
+
|
|
260
|
+
Cache prewarming builds the navigation registry directly without constructing
|
|
261
|
+
an empty-query result, symbol cards, pagination, or JSON payloads. Up to sixteen
|
|
262
|
+
recent ranked queries are retained in a small LRU so alternating CLI and
|
|
263
|
+
OpenCode searches remain warm.
|
|
254
264
|
|
|
255
265
|
`cache start` waits up to `--startup-timeout 120` seconds by default for a large
|
|
256
266
|
workspace to prewarm. The timeout belongs to the starting client and does not
|
|
@@ -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.
|
|
5
|
+
Version 2.2.0 is authored by Dark Light and supports Windows, macOS, and Linux.
|
|
6
6
|
|
|
7
7
|
## Install and quick start
|
|
8
8
|
|
|
@@ -199,19 +199,28 @@ above 80 percent.
|
|
|
199
199
|
|
|
200
200
|
Cold builds parse independent source units in short-lived processes created with
|
|
201
201
|
the cross-platform `spawn` method. `--workers auto|N` defaults to `auto`.
|
|
202
|
-
Automatic selection uses at most
|
|
202
|
+
Automatic selection uses at most eight worker processes, leaves one detected CPU
|
|
203
203
|
free, never exceeds the source task count, and—for the cache daemon—allows one
|
|
204
|
-
worker per `
|
|
205
|
-
task, CPU, and
|
|
204
|
+
worker per `64 MiB` of retained-cache budget. `view` and `index` use the same
|
|
205
|
+
task, CPU, and eight-worker caps without the cache-budget term. An explicit value
|
|
206
206
|
from 1 through 32 overrides the automatic CPU and memory caps but is still
|
|
207
207
|
limited by the number of tasks.
|
|
208
208
|
|
|
209
|
-
Worker processes
|
|
210
|
-
|
|
211
|
-
the
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
209
|
+
Worker processes build compact, detached navigation shards and exit before
|
|
210
|
+
retained-cache accounting. Full semantic object graphs and source text are not
|
|
211
|
+
retained in the parent. Tokenized source documents are loaded only for source
|
|
212
|
+
evidence requests such as `inspect`, and a byte-bounded LRU evicts older
|
|
213
|
+
documents. The transient worker memory remains separate from retained navigation
|
|
214
|
+
structures and the existing 80-percent warning. Retained bytes are maintained
|
|
215
|
+
incrementally; requests never traverse the complete cache object graph merely
|
|
216
|
+
to measure it. If an automatic pool fails before accepting a result, one
|
|
217
|
+
automatic serial fallback is attempted; explicit worker counts fail instead of
|
|
218
|
+
silently changing the requested configuration.
|
|
219
|
+
|
|
220
|
+
Cache prewarming builds the navigation registry directly without constructing
|
|
221
|
+
an empty-query result, symbol cards, pagination, or JSON payloads. Up to sixteen
|
|
222
|
+
recent ranked queries are retained in a small LRU so alternating CLI and
|
|
223
|
+
OpenCode searches remain warm.
|
|
215
224
|
|
|
216
225
|
`cache start` waits up to `--startup-timeout 120` seconds by default for a large
|
|
217
226
|
workspace to prewarm. The timeout belongs to the starting client and does not
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.2.0"
|
|
@@ -20,6 +20,8 @@ import threading
|
|
|
20
20
|
import time
|
|
21
21
|
from types import ModuleType
|
|
22
22
|
|
|
23
|
+
from watchfiles import watch
|
|
24
|
+
|
|
23
25
|
from ._version import __version__
|
|
24
26
|
from .agent_context import AgentContext
|
|
25
27
|
from .agent_protocol import AgentProtocolError
|
|
@@ -32,10 +34,15 @@ DEFAULT_IDLE_TIMEOUT = 1800
|
|
|
32
34
|
DEFAULT_STARTUP_TIMEOUT = 120.0
|
|
33
35
|
_MAX_MESSAGE_BYTES = 1024 * 1024
|
|
34
36
|
_CONNECTION_TIMEOUT = 2.0
|
|
37
|
+
_CLIENT_RESPONSE_TIMEOUT = 120.0
|
|
35
38
|
_MEMORY_SIZE = re.compile(r"^(?P<count>[1-9][0-9]*)(?P<suffix>[KMG]?)$", re.IGNORECASE)
|
|
36
39
|
_STARTUP_DIAGNOSTIC_BYTES = 16 * 1024
|
|
37
40
|
_STARTUP_TOKEN_RE = re.compile(r"(?i)(token\b[^\n\r]*?:?\s*['\"]?[A-Za-z0-9_-]+['\"]?|\b[a-zA-Z0-9_-]{32,})")
|
|
38
41
|
_START_LOCK_INCOMPLETE_GRACE_SECONDS = 1.0
|
|
42
|
+
_CACHE_REVISION_CHECK_INTERVAL_SECONDS = 3600.0
|
|
43
|
+
_WATCHED_SUFFIXES = frozenset(
|
|
44
|
+
{".pas", ".pp", ".inc", ".dpr", ".dpk", ".dproj", ".cfg"}
|
|
45
|
+
)
|
|
39
46
|
|
|
40
47
|
|
|
41
48
|
def estimate_deep_size(value: object) -> int:
|
|
@@ -475,7 +482,7 @@ def _start_lock(root: str | Path, timeout: float):
|
|
|
475
482
|
def _client_exchange(metadata: CacheMetadata, request: dict[str, object]) -> CacheClientResponse:
|
|
476
483
|
try:
|
|
477
484
|
with socket.create_connection(("127.0.0.1", metadata.port), timeout=2) as connection:
|
|
478
|
-
connection.settimeout(
|
|
485
|
+
connection.settimeout(_CLIENT_RESPONSE_TIMEOUT)
|
|
479
486
|
request_without_token = {key: value for key, value in request.items() if key != "token"}
|
|
480
487
|
connection.sendall(json.dumps({"token": metadata.token, **request_without_token}, separators=(",", ":")).encode("utf-8") + b"\n")
|
|
481
488
|
response = _read_line(connection)
|
|
@@ -541,6 +548,7 @@ class _CacheService:
|
|
|
541
548
|
metadata.project_file or None,
|
|
542
549
|
workers=metadata.workers,
|
|
543
550
|
worker_memory_budget_bytes=metadata.max_memory_bytes,
|
|
551
|
+
revision_check_interval_seconds=_CACHE_REVISION_CHECK_INTERVAL_SECONDS,
|
|
544
552
|
)
|
|
545
553
|
self.budget = CacheBudget(metadata.max_memory_bytes)
|
|
546
554
|
self.stats = CacheStats()
|
|
@@ -556,15 +564,14 @@ class _CacheService:
|
|
|
556
564
|
def prewarm(self) -> None:
|
|
557
565
|
started = time.monotonic()
|
|
558
566
|
try:
|
|
559
|
-
self.context.
|
|
560
|
-
self.last_revision = self.context.workspace.workspace_revision
|
|
567
|
+
self.last_revision = self.context.prewarm_navigation()
|
|
561
568
|
self.cache_state = "warm"
|
|
562
569
|
except AgentProtocolError as error:
|
|
563
570
|
if error.code != "project_required":
|
|
564
571
|
raise
|
|
565
572
|
self.cache_state = "ready"
|
|
566
573
|
self.last_budget = self.budget.enforce(
|
|
567
|
-
measure=lambda:
|
|
574
|
+
measure=lambda: self.context.estimated_cache_bytes,
|
|
568
575
|
evict_auxiliary=self.context.evict_auxiliary_caches,
|
|
569
576
|
evict_navigation=self.context.evict_navigation_caches,
|
|
570
577
|
)
|
|
@@ -605,7 +612,7 @@ class _CacheService:
|
|
|
605
612
|
if before != after:
|
|
606
613
|
self.stats.invalidations += 1
|
|
607
614
|
self.last_budget = self.budget.enforce(
|
|
608
|
-
measure=lambda:
|
|
615
|
+
measure=lambda: self.context.estimated_cache_bytes,
|
|
609
616
|
evict_auxiliary=self.context.evict_auxiliary_caches,
|
|
610
617
|
evict_navigation=self.context.evict_navigation_caches,
|
|
611
618
|
)
|
|
@@ -642,10 +649,31 @@ class _CacheService:
|
|
|
642
649
|
"parallel_seconds": self.context.parallel_stats.elapsed_seconds,
|
|
643
650
|
"parallel_fallbacks": self.stats.parallel_fallbacks,
|
|
644
651
|
"idle_timeout": self.metadata.idle_timeout, "idle_remaining": max(0.0, self.metadata.idle_timeout - idle),
|
|
645
|
-
"workspace_revision": self.
|
|
652
|
+
"workspace_revision": self.last_revision,
|
|
646
653
|
}
|
|
647
654
|
|
|
648
655
|
|
|
656
|
+
def _watch_filter(_change: object, path: str) -> bool:
|
|
657
|
+
return Path(path).suffix.casefold() in _WATCHED_SUFFIXES
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
def _watch_workspace(service: _CacheService) -> None:
|
|
661
|
+
try:
|
|
662
|
+
for changes in watch(
|
|
663
|
+
service.metadata.root,
|
|
664
|
+
watch_filter=_watch_filter,
|
|
665
|
+
stop_event=service.shutdown,
|
|
666
|
+
debounce=50,
|
|
667
|
+
step=20,
|
|
668
|
+
recursive=True,
|
|
669
|
+
raise_interrupt=False,
|
|
670
|
+
):
|
|
671
|
+
if changes:
|
|
672
|
+
service.context.invalidate_revision_cache()
|
|
673
|
+
except (OSError, RuntimeError):
|
|
674
|
+
service.context.invalidate_revision_cache()
|
|
675
|
+
|
|
676
|
+
|
|
649
677
|
def _serve_connection(connection: socket.socket, service: _CacheService) -> None:
|
|
650
678
|
try:
|
|
651
679
|
line = _read_line(connection)
|
|
@@ -691,9 +719,17 @@ def run_cache_daemon(
|
|
|
691
719
|
idle_timeout,
|
|
692
720
|
time.time(),
|
|
693
721
|
)
|
|
722
|
+
watcher: threading.Thread | None = None
|
|
694
723
|
try:
|
|
695
724
|
service = _CacheService(metadata)
|
|
696
725
|
service.prewarm()
|
|
726
|
+
watcher = threading.Thread(
|
|
727
|
+
target=_watch_workspace,
|
|
728
|
+
args=(service,),
|
|
729
|
+
name="delphi-cache-watcher",
|
|
730
|
+
daemon=True,
|
|
731
|
+
)
|
|
732
|
+
watcher.start()
|
|
697
733
|
_write_metadata(metadata)
|
|
698
734
|
while not service.shutdown.is_set() and time.monotonic() - service.last_activity < idle_timeout:
|
|
699
735
|
try:
|
|
@@ -704,6 +740,10 @@ def run_cache_daemon(
|
|
|
704
740
|
connection.settimeout(_CONNECTION_TIMEOUT)
|
|
705
741
|
_serve_connection(connection, service)
|
|
706
742
|
finally:
|
|
743
|
+
if "service" in locals():
|
|
744
|
+
service.shutdown.set()
|
|
745
|
+
if watcher is not None:
|
|
746
|
+
watcher.join(timeout=2.0)
|
|
707
747
|
listener.close()
|
|
708
748
|
_remove_metadata_if_owned(metadata)
|
|
709
749
|
|