graphite-code 0.5.1__tar.gz → 0.5.2__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.
- {graphite_code-0.5.1 → graphite_code-0.5.2}/CHANGELOG.md +29 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/PKG-INFO +1 -1
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/__init__.py +1 -1
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/buildlock.py +53 -3
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/cli.py +3055 -3053
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/daemon.py +782 -745
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_build_detach.py +15 -6
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_buildlock.py +52 -1
- graphite_code-0.5.2/tests/test_daemon_build_lock.py +158 -0
- graphite_code-0.5.2/tests/test_daemon_child_lock.py +104 -0
- graphite_code-0.5.1/tests/test_daemon_build_lock.py +0 -83
- {graphite_code-0.5.1 → graphite_code-0.5.2}/.gitignore +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/ARCHITECTURE.md +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/CONTRIBUTING.md +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/LICENSE +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/README.md +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/RELEASING.md +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/pyproject.toml +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/__main__.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/_cleanup_worker.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/agent_hooks.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/agent_settings.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/analyze.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/answer_contract.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/bootstrap.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/cache.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/channel.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/cluster.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/config.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/context.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/daemon_health.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/debt.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/dependency_install.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/detach.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/doctor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/doctor_probes.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/engine_identity.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/export/__init__.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/export/html.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/export/json.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/export/md.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/extract/__init__.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/extract/ast.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/freshness.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/git.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/graph.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/graph_io.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/health.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/hook_entry.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/hookinstall.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/hookshim.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/incident_ledger.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/ingest.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/init.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/io.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/listing.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/llm.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/llm_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/mcp.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/mcp_server.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/natural_query.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/overlays.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/probe_process.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/probe_workspace.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/process_contracts.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/provider_observer.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/query.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/query_plan.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/replacement_audit.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/resolve.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/review.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/__init__.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/approval.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/classifier.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/claude_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/claude_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/cli_identity.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/codex_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/codex_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/context_builder.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/contracts.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/diff_policy.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/edit_apply.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/effort.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/lifecycle.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/lifecycle_operator.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/lifecycle_service.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/lifecycle_storage.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/ollama_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/ollama_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/openrouter_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/openrouter_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/policy.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/probe_runner.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/process_runner.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/profiles.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/prompt.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/registry.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/route_pool.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/route_pool_execution.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/schema_validation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/service.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/settings.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/shadow.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/storage.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/telemetry.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/worktree.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/zai_edit.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/zai_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/routing/zai_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/savings.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/ts_bridge.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/ts_resolver.mjs +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/typescript_activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/usage_ledger.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/validation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/watch.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/windows_job.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/windows_startup.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/src/graphite/windows_task.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/conftest.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/data/sqloracle/blindspots.py.txt +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/data/sqloracle/round69.py.txt +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/fake_clis/fake_cli.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/fixtures/provider_lifecycle_schema_v1.sql +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/fixtures/routing_schema_v2_ca77600.sql +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/fixtures/routing_schema_v3_94eb333.sql +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/fixtures/routing_schema_v4_lifecycle_migration.sql +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_activation_backstop.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_agent_hook_activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_agent_hooks.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_agent_settings.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_answer_contract.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_arrow_and_constructor_binding.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_atomic_write.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_bootstrap.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_cache_engine_identity.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_cache_file_set.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_cache_pruning.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_call_graph.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_cli.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_core.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_lock.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_mcp.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_register.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_report.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_channel_status.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_class_field_arrow_binding.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_cli_channel.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_cli_version.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_context.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_cwd_relative_config.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_daemon.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_daemon_activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_daemon_engine_staleness.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_daemon_health.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_daemon_health_activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_debt.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_destructured_binding.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_determinism.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_dispatch_evidence.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_doctor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_doctor_agent_hooks.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_doctor_hooks.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_doctor_managed_docs.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_documentation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_edit_apply.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_engine_identity.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_external_calls.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_git_security.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_go_rust.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_graph_io.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_graph_provider_isolation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_hardening.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_health.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_hook_entry.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_hook_template.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_hookinstall.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_hookshim.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_html_security.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_incident_ledger.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_init.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_init_activation_doctrine.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_init_hooks.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_init_validation_exit.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_lifecycle_operator.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_listing.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_listing_surfaces.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_llm.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_mcp.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_method_dispatch_scope.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_monorepo.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_natural_query.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_node_identity.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_overlays.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_path_leak_fixture.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_probe_diagnostics.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_probe_workspace.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_claude_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_codex_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_lifecycle.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_lifecycle_service.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_lifecycle_storage.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_observer.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_ollama_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_openrouter_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_provider_probe_runner.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_public_surface.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_published_schemas.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_python_resolver.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_query_plan.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_reliability.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_replacement_audit.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_resolve.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_review.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_route_pool.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_approval.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_benchmark.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_classifier.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_claude_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_cli.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_cli_contracts.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_cli_recovery.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_codex_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_context.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_contracts.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_diff_policy.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_openrouter_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_policy.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_process_runner.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_profiles.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_registry.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_schema_validation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_security.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_service.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_shadow.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_storage.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_telemetry.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_worktree.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_zai_executor.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_routing_zai_probe.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_savings.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_search.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_smoke.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_sqloracle.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_typescript_activation.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_typescript_resolver.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_usage_ledger.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_verify_artifact.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_verify_published_release.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_watch.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_windows_startup.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_windows_task.py +0 -0
- {graphite_code-0.5.1 → graphite_code-0.5.2}/tests/test_zai_edit.py +0 -0
|
@@ -12,6 +12,35 @@ machine-checkable identity; the version is for humans.
|
|
|
12
12
|
|
|
13
13
|
[Keep a Changelog]: https://keepachangelog.com/en/1.1.0/
|
|
14
14
|
|
|
15
|
+
## [0.5.2] — 2026-08-28
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
**Force-stopping the daemon mid-build no longer wedges its successor for the
|
|
20
|
+
lock TTL** (#60). The build lock was held by the daemon on its child's behalf
|
|
21
|
+
(`ENV_LOCK_HELD` told the child not to contend), so `Stop-Process -Force` --
|
|
22
|
+
the documented post-install restart, which runs no `finally` -- left
|
|
23
|
+
`.build.lock` on disk naming a dead pid while the orphaned child kept writing
|
|
24
|
+
`graph-out/`. The successor could neither trust "holder dead" (the writer was
|
|
25
|
+
still alive) nor see "writer done", so it logged `build_skipped_locked` every
|
|
26
|
+
cycle and `daemon-health` warned for up to 600 s over a graph that was already
|
|
27
|
+
correct. A pid-liveness probe would not have helped and would have raced the
|
|
28
|
+
orphan in the very incident that filed the issue.
|
|
29
|
+
|
|
30
|
+
The lock now follows the writer: the daemon's child takes it itself, exactly
|
|
31
|
+
as a hook or manual `graphite build` does, and a killed daemon leaves no lock
|
|
32
|
+
at all. `build_skipped_locked` is therefore true for as long as a build is
|
|
33
|
+
really running and not a second longer. Two consequences are handled. The
|
|
34
|
+
child answers a refusal with exit status 75 (`EX_TEMPFAIL`) when the daemon
|
|
35
|
+
asks for it via `GRAPHITE_BUILD_LOCK_REPORT_REFUSAL`, so the cycle can book
|
|
36
|
+
"another builder owns the repo" as a skip and not a failed build; a human or a
|
|
37
|
+
hook still gets exit 0. And because the daemon's timeout kill now kills the
|
|
38
|
+
holder, the daemon releases the lock its dead child left -- by pid match only,
|
|
39
|
+
never by guessing. Under a Windows venv launcher `Popen.pid` is the launcher,
|
|
40
|
+
not the writer, so there the timeout path falls back to the TTL instead of
|
|
41
|
+
retrying next cycle: conservative by design, and noted here so nobody reads it
|
|
42
|
+
as a hang. `GRAPHITE_BUILD_LOCK_HELD` is gone; nothing outside the daemon set it.
|
|
43
|
+
|
|
15
44
|
## [0.5.1] — 2026-08-27
|
|
16
45
|
|
|
17
46
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: graphite-code
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: Local-first, zero-LLM knowledge graph extraction for codebases.
|
|
5
5
|
Project-URL: Homepage, https://github.com/jared0565/graphite
|
|
6
6
|
Project-URL: Repository, https://github.com/jared0565/graphite
|
|
@@ -38,4 +38,4 @@ __all__ = ["__version__"]
|
|
|
38
38
|
#: Coarse and hand-maintained by construction. It is a release label, not
|
|
39
39
|
#: evidence that a given fix is present -- to answer that, survey for the marker
|
|
40
40
|
#: the fix introduced, or compare `graphite --version` fingerprints.
|
|
41
|
-
__version__ = "0.5.
|
|
41
|
+
__version__ = "0.5.2"
|
|
@@ -9,6 +9,14 @@ Staleness is TTL-only, deliberately. `os.kill(pid, 0)` is the obvious liveness
|
|
|
9
9
|
idiom and is WRONG here: on Windows, Python's `os.kill` ignores signal 0 and
|
|
10
10
|
calls TerminateProcess, so the portable-looking probe would kill the very
|
|
11
11
|
process it was checking.
|
|
12
|
+
|
|
13
|
+
The holder must be the process that writes (#60). The daemon used to take the
|
|
14
|
+
lock and hand its child an escape hatch; force-stopping the daemon then left
|
|
15
|
+
the record on disk with a dead pid while the orphaned child kept writing
|
|
16
|
+
graph-out/, and the successor could neither trust "holder dead" nor see
|
|
17
|
+
"writer done" -- so it skipped the repo for the whole TTL. Liveness probing
|
|
18
|
+
would not have helped: the recorded pid was dead while the writer was alive.
|
|
19
|
+
With the writer as holder, its death and its writes end together.
|
|
12
20
|
"""
|
|
13
21
|
from __future__ import annotations
|
|
14
22
|
|
|
@@ -24,9 +32,13 @@ from typing import Any, Callable, Iterator
|
|
|
24
32
|
# holding the lock past double the daemon's give-up point is dead by definition.
|
|
25
33
|
DEFAULT_TTL_SECONDS = 600.0
|
|
26
34
|
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
|
|
35
|
+
# A builder that cannot take the lock exits 0: a skipped build is a normal
|
|
36
|
+
# outcome for a human or a git hook, not a failure. The daemon needs more --
|
|
37
|
+
# "another builder owns the repo" must not be booked as a failed build -- so
|
|
38
|
+
# it sets this in its child's environment, and the child answers a refusal
|
|
39
|
+
# with REFUSED_EXIT_STATUS instead. Mirrors the GRAPHITE_DAEMON_CHILD convention.
|
|
40
|
+
ENV_REPORT_REFUSAL = "GRAPHITE_BUILD_LOCK_REPORT_REFUSAL"
|
|
41
|
+
REFUSED_EXIT_STATUS = 75 # sysexits.h EX_TEMPFAIL: try again later
|
|
30
42
|
|
|
31
43
|
|
|
32
44
|
def lock_path(cache_dir: Path) -> Path:
|
|
@@ -50,6 +62,44 @@ def _is_stale(record: dict[str, Any] | None, now: float, ttl_seconds: float) ->
|
|
|
50
62
|
return (now - float(started)) > ttl_seconds
|
|
51
63
|
|
|
52
64
|
|
|
65
|
+
def is_held(
|
|
66
|
+
cache_dir: Path,
|
|
67
|
+
*,
|
|
68
|
+
ttl_seconds: float = DEFAULT_TTL_SECONDS,
|
|
69
|
+
clock: Callable[[], float] = time.time,
|
|
70
|
+
) -> bool:
|
|
71
|
+
"""Advisory: would a builder be refused right now?
|
|
72
|
+
|
|
73
|
+
Reads only -- never acquires, never unlinks, never steals. The answer can
|
|
74
|
+
be stale by the time the caller acts on it, so correctness still rests on
|
|
75
|
+
the acquirer's own `build_lock`. The daemon uses it to avoid spawning a
|
|
76
|
+
child every cycle only to have it refused.
|
|
77
|
+
"""
|
|
78
|
+
path = lock_path(cache_dir)
|
|
79
|
+
if not path.exists():
|
|
80
|
+
return False
|
|
81
|
+
return not _is_stale(_read_record(path), clock(), ttl_seconds)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def release_if_held_by(cache_dir: Path, *, pid: int) -> bool:
|
|
85
|
+
"""Unlink the lock if its record names `pid`; True if it did.
|
|
86
|
+
|
|
87
|
+
For a parent that has just killed `pid`: the child died without its
|
|
88
|
+
`finally`, and no other process can hold a record carrying its pid, so this
|
|
89
|
+
releases on the dead child's behalf rather than stealing. It is NOT a
|
|
90
|
+
liveness probe -- the caller must already know the process is dead.
|
|
91
|
+
"""
|
|
92
|
+
path = lock_path(cache_dir)
|
|
93
|
+
record = _read_record(path)
|
|
94
|
+
if record is None or record.get("pid") != pid:
|
|
95
|
+
return False
|
|
96
|
+
try:
|
|
97
|
+
path.unlink()
|
|
98
|
+
except OSError:
|
|
99
|
+
return False
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
|
|
53
103
|
def _create_exclusive(path: Path, now: float) -> bool:
|
|
54
104
|
"""Atomically create the lock file. False if someone else already has it."""
|
|
55
105
|
try:
|