execweave 0.8.13__tar.gz → 0.8.14__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.
- {execweave-0.8.13 → execweave-0.8.14}/PKG-INFO +1 -1
- {execweave-0.8.13 → execweave-0.8.14}/pyproject.toml +2 -2
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/__init__.py +1 -1
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/collector.py +38 -15
- execweave-0.8.14/tests/test_pypi_0813_cleanup.py +382 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v069_dashboard_release.py +3 -3
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/ci.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/cleanup-workflow-history.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/i18n.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/package-benchmark.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/package-smoke.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/provider-capability-stage-integrity.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/provider-dashboard-contract.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/publish.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/scalability.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/viewer-agent-isolation.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/wheel-smoke.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.github/workflows/windows-launcher.yml +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/.gitignore +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/LICENSE +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/README.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/benchmarks/phase1_overhead.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/acceptance_hardening_20260906.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/audit_eight_children.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/audit_python_journey.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/audit_real_clicks.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/current_state_reaudit.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/execweave_full_audit.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/gate_status.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/gate_status_history_through_g3.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/github_pr_inventory.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/handoff_checkpoint_20260906.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/next_agent_handoff.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/diagnostics/pr_regression_map.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/antigravity-hooks.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/assets/codex.gif +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/benchmarks/README.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/benchmarks/v0.6.0-github-actions.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/benchmarks/v0.6.0-github-actions.svg +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/claude-code-hooks.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/codex-hooks.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/cursor-hooks.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/evidence-grades.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/inference-gateway.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/internal/provider-capability-matrix.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/live-graph.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/model-runtime.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/opencode-plugin.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-1-runtime-collection.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/phase-2-execution-graph.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/remaining-provider-audit-v0.8.7.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/rule-packs.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/run-integrity.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/runtime-threat-model.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/security-analysis.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.de.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.fr.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.ja.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.ko.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.ru.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.zh-CN.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/semantic-telemetry.zh-TW.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/v0.6.5-hardening-decisions.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/docs/v0.8.3-graph-ergonomics.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/_check_release_stage_integrity_impl.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/_dashboard_acceptance_impl.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/_ollama_interactive_acceptance_impl.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/_ollama_visible_acceptance_impl.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/_python_native_acceptance_impl.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/__init__.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/browser_diagnostics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/contracts.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/g5_runner.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/g6_runner.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/interrupt_guard.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/processes.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/reporting.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/acceptance/terminal_output.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/annotate_pytest_failures.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/audit_i18n_parity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_claude_hook.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_claude_record_graph.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_codex_hook.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_conversation_records.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_correlation_graph.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_inference_gateway_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_model_runtime_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_openai_compatible_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_release_stage_integrity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_semantic_graph.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_viewer_js.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_wheel_install.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/check_windows_launchers.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/dashboard_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/emit_claude_hook_smoke.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/emit_codex_hook_smoke.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/emit_cursor_hook_smoke.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/emit_opencode_plugin_smoke.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/make_semantic_smoke.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/measure_graph_metrics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/ollama_interactive_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/ollama_visible_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/owned_cleanup_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/probe_provider_capability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/python_native_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/scripts/sync_i18n_nav.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/__main__.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/_conversation_records_core.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/_dashboard_shell_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/_http_proxy_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/_http_proxy_bounded.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/_http_proxy_stage.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/agent_bootstrap.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/agent_topology.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/agent_trace.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/agy_preview_sanitize.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/analysis.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/anthropic.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/anthropic_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/anthropic_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_adapter_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_full_fidelity_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_hook_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_subagent_linkage.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/antigravity_trace_capability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/auto_specialized.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/backends.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/benchmark.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_child_transcript.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_delegation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_hook_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_hook_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_model_observer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/claude_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_conversation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_hook_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_hook_entry.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_hook_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_message_diagnostics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_message_transport_diagnostics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_rollout_structures.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_rollout_trace.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/codex_rollout_trace_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/command.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/content_evidence.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/content_store.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_archive.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_message_identity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_antigravity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_claude.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_codex.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_common.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_generic.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_lines.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_preview_transcript.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_records.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_records_antigravity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_records_codex.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_records_common.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/conversation_records_ollama.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/correlation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_delegation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_delegation_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_hook_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_hook_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/cursor_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/dashboard_shell.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/entry.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/evidence_availability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/evidence_grade.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/filesystem.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/focus.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/graph.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/graph_ops.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/http_proxy.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/http_proxy_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/inference_gateway.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/inference_gateway_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/inference_gateway_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/inference_identity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/inference_identity_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/integrity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/integrity_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/litellm_callback.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/litellm_callback_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_core.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_extra_style.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_markup.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_process_layout.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_readability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_script_a.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_script_b.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_script_c.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_script_d.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/live_view_style.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/model_runtime.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/model_runtime_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/model_runtime_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/openai_compatible.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/openai_compatible_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/openai_compatible_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_event_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_hook_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_plugin_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/opencode_task_linkage.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/overhead_benchmark.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/provider_capability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/provider_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/provider_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/rule_pack.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/rule_pack_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/scalability_benchmark.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/schema.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/scope.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/semantic.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/sink.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/strace_backend.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/stream_assembly.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/theme.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/top.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/top_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/validate.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/vendor/dagre.min.js +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/view_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_claude.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_codex.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_cursor.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_default.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_ollama.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_opencode.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_agent_panel_registry.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_content_inspector.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_dashboard_clean.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_dashboard_focus.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_dashboard_hardening.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_external_endpoints.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_limits.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_live_layout.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_projection.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_projection_base.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/viewer_semantic_projection.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/src/execweave/workflow.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/dashboard_readability_fixture.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/codex_multi_agent/PROVENANCE.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/codex_multi_agent/hook-payloads.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/codex_multi_agent/rollout-main.jsonl +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/hooks/README.md +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/hooks/claude.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/hooks/codex.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/hooks/cursor.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/hooks/manifest.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/fixtures/hooks/opencode.json +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/multi_agent_run_fixture.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_browser_diagnostics_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_conpty_selection.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_interrupt_guard.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_owned_processes.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_required_capabilities.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_terminal_output.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_acceptance_visible_pipe.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_bootstrap.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_message_viewer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_node_labels.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_said_panel.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_topology_evidence.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_trace_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agent_trace_viewer_visibility.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_agy_windows_wire_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_analysis.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_anthropic.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_agent_collaboration.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_child_panel_policy.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_child_transcript_tools.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_cursor_launch.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_field_run_regressions.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_history_replay.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_identity_topology.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_invocation_archive.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_linkage_projection.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_multi_conversation_isolation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_official_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_role_path_fallback.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_root_child_history_v2.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_subagent_transcript_linkage.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_antigravity_trace_capability_cli.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_auto_specialized.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_auto_specialized_ollama_two_phase.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_backends.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_child_transcript_tools.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_delegation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_hook_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_hook_metadata.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_hook_viewer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_model_observer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_claude_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cleanup_finalizer_identity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_archive_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_child_panel_policy.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_conversation_isolation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_hook_global_fail_open.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_hook_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_hook_partial_capture.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_interrupt_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_message_diagnostics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_message_transport_diagnostics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_nickname_path_fallback.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_plain_routed_agent_message.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_real_multi_agent_conversation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_reducer_command.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_rollout_structures.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_rollout_trace.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_codex_routing_native_identity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_collector.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_command.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_condense.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_access.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_agent_focus.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_agent_isolation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_identity_merge.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_message_observation_dedupe.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_provider_parity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_conversation_root_authority.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_correlation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_correlation_canonical_path.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_correlation_checker.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_correlation_process_exe.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cross_provider_agent_trace.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_delegation.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_hook_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_hook_fail_open.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_ollama_session_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_cursor_task_linkage.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dagre_semantic_pipeline.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_acceptance_relative_output_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_acceptance_reporting.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_camera_scheduler_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_favicon.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_gif_export_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_information_architecture.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_initial_fit_readability_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_node_drag_camera_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_readability_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_round_fold_state_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_simplification.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_dashboard_ux_and_hook_projection.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_delegation_viewer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_evidence_grade.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_execution_viewer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_external_endpoints_all_providers.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_filesystem_resilience.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_focus.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_fold_budget_setting.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_g5_hardening_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_g6_owned_parity_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph_arrange_constraints_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph_clear_focus_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph_edge_routing_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph_lane_separation_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph_node_sizing_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_graph_ops.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_hook_fixture_corpus.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_http_proxy.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_http_proxy_request_phase.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_http_proxy_response_memory.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_http_proxy_streaming.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_i18n_readme_policy.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_inference_endpoint_identity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_inference_gateway.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_inference_gateway_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_inference_identity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_integrity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_litellm_callback.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live_auth.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live_dashboard.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live_dashboard_js.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live_delta.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live_logs_export.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_live_theme.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_lmstudio_auto_specialized.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_local_runtime_live_capture.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_model_runtime.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_model_runtime_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_ollama_interactive_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_ollama_interactive_terminal_semantics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_ollama_panel_policy.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_ollama_serve_runtime_integration.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_ollama_visible_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_openai_compatible.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_adapter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_event_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_event_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_full_fidelity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_identity_unification.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_plugin.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_record.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_opencode_task_session_linkage.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_overhead_benchmark.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_per_agent_conversation_default.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_pr25_premerge_hardening_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_pr25_premerge_hardening_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_pro6_audit_regressions.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_process_tree_layout.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_provider_capability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_provider_conversation_evidence.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_provider_conversation_history_integrity.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_provider_dashboard_contract.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_provider_lifecycle.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_provider_neutral_viewer_semantics.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_pypi_0812_regressions.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_python_native_acceptance.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_relay_prompt_live_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_release_stage_integrity_version_guard.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_rule_pack.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_schema.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_scope.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_semantic.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_shared_injected_context_scope.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_single_agent_barycenter.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_strace_backend.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_stream_assembly.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_threat_model.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_tool_traffic_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_top_detached.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v063_features.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v064_live_auto_integrations.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v064_live_evidence.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v079_review_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v079_review_regressions.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_v083_release_gate_p2.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_validate.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_version.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_viewer.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_viewer_agent_isolation_e2e.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_viewer_child_authority.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_viewer_content_inspector.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_viewer_limits.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_viewer_projection.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_visual_ux_readability.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_windows_codex_agy_display_repair.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tests/test_workflow.py +0 -0
- {execweave-0.8.13 → execweave-0.8.14}/tools/verify_metrics_tool.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: execweave
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.14
|
|
4
4
|
Summary: Turn AI-agent runtime behavior into a local interactive execution graph.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Irish-kw/ExecWeave
|
|
6
6
|
Project-URL: Repository, https://github.com/Irish-kw/ExecWeave
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execweave"
|
|
7
|
-
# ExecWeave v0.8.
|
|
8
|
-
version = "0.8.
|
|
7
|
+
# ExecWeave v0.8.14 release metadata
|
|
8
|
+
version = "0.8.14"
|
|
9
9
|
description = "Turn AI-agent runtime behavior into a local interactive execution graph."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -123,6 +123,7 @@ class RuntimeCollector:
|
|
|
123
123
|
self.collect_filesystem = collect_filesystem
|
|
124
124
|
self.collect_network = collect_network
|
|
125
125
|
self._seen_processes: dict[int, ProcessSnapshot] = {}
|
|
126
|
+
self._discovered_processes: dict[int, ProcessSnapshot] = {}
|
|
126
127
|
self._seen_connections: set[tuple[str, str | None, str | None, str]] = set()
|
|
127
128
|
self._network_sample_attempts = 0
|
|
128
129
|
self._network_sample_successes = 0
|
|
@@ -195,6 +196,7 @@ class RuntimeCollector:
|
|
|
195
196
|
)
|
|
196
197
|
|
|
197
198
|
process: subprocess.Popen[bytes] | None = None
|
|
199
|
+
owned: list[psutil.Process] = []
|
|
198
200
|
return_code = 1
|
|
199
201
|
interrupted = False
|
|
200
202
|
collector_error_type: str | None = None
|
|
@@ -230,8 +232,6 @@ class RuntimeCollector:
|
|
|
230
232
|
except KeyboardInterrupt:
|
|
231
233
|
interrupted = True
|
|
232
234
|
return_code = 130
|
|
233
|
-
if process is not None:
|
|
234
|
-
self._terminate_process_tree(process)
|
|
235
235
|
|
|
236
236
|
if not interrupted:
|
|
237
237
|
run_post_command_specialized_probe(
|
|
@@ -241,16 +241,24 @@ class RuntimeCollector:
|
|
|
241
241
|
return return_code
|
|
242
242
|
except BaseException as exc:
|
|
243
243
|
collector_error_type = type(exc).__name__
|
|
244
|
-
if process is not None and self._owned_live_processes(process):
|
|
245
|
-
self._terminate_process_tree(process)
|
|
246
|
-
workload_terminated_due_to_collector_error = True
|
|
247
244
|
raise
|
|
248
245
|
finally:
|
|
246
|
+
# A workload exception is a nonzero child exit, not an exception in
|
|
247
|
+
# this collector. Finalize observed descendants on every exit path,
|
|
248
|
+
# including successful launchers that leave reparented children.
|
|
249
|
+
if process is not None:
|
|
250
|
+
owned = self._owned_live_processes(process)
|
|
251
|
+
workload_terminated_due_to_collector_error = (
|
|
252
|
+
collector_error_type is not None and bool(owned)
|
|
253
|
+
)
|
|
254
|
+
self._terminate_process_tree(process, owned=owned)
|
|
249
255
|
if watcher is not None:
|
|
250
256
|
watcher.stop()
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
257
|
+
# A failed termination must not become a false clean result merely
|
|
258
|
+
# because the selected child has since reparented out of the tree.
|
|
259
|
+
workload_alive_after_cleanup = any(
|
|
260
|
+
self._process_is_live(candidate) for candidate in owned
|
|
261
|
+
) or bool(process is not None and self._owned_live_processes(process))
|
|
254
262
|
self.sink.emit(
|
|
255
263
|
RuntimeEvent.create(
|
|
256
264
|
session_id=self.session_id,
|
|
@@ -293,12 +301,13 @@ class RuntimeCollector:
|
|
|
293
301
|
def _process_for_snapshot(self, snapshot: ProcessSnapshot) -> psutil.Process | None:
|
|
294
302
|
try:
|
|
295
303
|
process = psutil.Process(snapshot.pid)
|
|
304
|
+
# Cleanup needs identity, not readable exe/name/cmdline metadata.
|
|
305
|
+
# Never treat a reused PID as the process we originally observed.
|
|
306
|
+
if process.create_time() != snapshot.create_time:
|
|
307
|
+
return None
|
|
308
|
+
return process
|
|
296
309
|
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
297
310
|
return None
|
|
298
|
-
current = _safe_process_snapshot(process)
|
|
299
|
-
if current is None or not self._same_process_lifetime(snapshot, current):
|
|
300
|
-
return None
|
|
301
|
-
return process
|
|
302
311
|
|
|
303
312
|
def _owned_live_processes(
|
|
304
313
|
self,
|
|
@@ -331,15 +340,24 @@ class RuntimeCollector:
|
|
|
331
340
|
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
332
341
|
pass
|
|
333
342
|
|
|
334
|
-
|
|
343
|
+
snapshots = {**self._seen_processes, **self._discovered_processes}
|
|
344
|
+
for snapshot in snapshots.values():
|
|
335
345
|
tracked = self._process_for_snapshot(snapshot)
|
|
336
346
|
if tracked is not None:
|
|
337
347
|
add_with_descendants(tracked)
|
|
338
348
|
|
|
339
349
|
return list(owned.values())
|
|
340
350
|
|
|
341
|
-
def _terminate_process_tree(
|
|
342
|
-
|
|
351
|
+
def _terminate_process_tree(
|
|
352
|
+
self,
|
|
353
|
+
process: subprocess.Popen[bytes],
|
|
354
|
+
*,
|
|
355
|
+
owned: list[psutil.Process] | None = None,
|
|
356
|
+
) -> None:
|
|
357
|
+
# A caller's selection must survive reparenting between discovery and
|
|
358
|
+
# termination. Re-querying here can lose children we just proved owned.
|
|
359
|
+
if owned is None:
|
|
360
|
+
owned = self._owned_live_processes(process)
|
|
343
361
|
# Terminate descendants/tracked orphans before the launcher/root when it is
|
|
344
362
|
# still alive. Holding psutil handles also keeps cleanup robust if a parent
|
|
345
363
|
# exits while the loop is running.
|
|
@@ -392,6 +410,11 @@ class RuntimeCollector:
|
|
|
392
410
|
current[snapshot.pid] = snapshot
|
|
393
411
|
process_objects[snapshot.pid] = proc
|
|
394
412
|
|
|
413
|
+
# Preserve the complete discovered tree before any event/network callback
|
|
414
|
+
# can raise. _seen_processes only contains successfully registered starts;
|
|
415
|
+
# a root callback can fail after its children have already reparented.
|
|
416
|
+
# Retain only the latest sample here, not an unbounded lifetime history.
|
|
417
|
+
self._discovered_processes = current
|
|
395
418
|
for snapshot in current.values():
|
|
396
419
|
previous = self._seen_processes.get(snapshot.pid)
|
|
397
420
|
if previous is None or not self._same_process_lifetime(previous, snapshot):
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"""D003: exercise real run/finalization, not a pre-seeded ownership dictionary."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import signal
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import time
|
|
10
|
+
from dataclasses import replace
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import psutil
|
|
14
|
+
import pytest
|
|
15
|
+
|
|
16
|
+
import execweave.collector as collector_module
|
|
17
|
+
from execweave.collector import RuntimeCollector, _safe_process_snapshot
|
|
18
|
+
from execweave.sink import JsonlSink
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
_LEAF = "import time; time.sleep(60)"
|
|
22
|
+
_CHILD = r'''
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
import time
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
leaf = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(60)"])
|
|
31
|
+
Path(sys.argv[1]).write_text(json.dumps([os.getpid(), leaf.pid]), encoding="utf-8")
|
|
32
|
+
Path(sys.argv[2]).touch()
|
|
33
|
+
time.sleep(60)
|
|
34
|
+
'''
|
|
35
|
+
_PARENT = r'''
|
|
36
|
+
import subprocess
|
|
37
|
+
import sys
|
|
38
|
+
import time
|
|
39
|
+
from pathlib import Path
|
|
40
|
+
|
|
41
|
+
subprocess.Popen([sys.executable, "-c", sys.argv[1], sys.argv[2], sys.argv[3]])
|
|
42
|
+
while not Path(sys.argv[4]).exists():
|
|
43
|
+
time.sleep(0.01)
|
|
44
|
+
if sys.argv[5] == "workload_exception":
|
|
45
|
+
raise RuntimeError("D003 workload exception")
|
|
46
|
+
sys.exit(int(sys.argv[5]))
|
|
47
|
+
'''
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _live(process: psutil.Process) -> bool:
|
|
51
|
+
try:
|
|
52
|
+
return process.is_running() and process.status() != psutil.STATUS_ZOMBIE
|
|
53
|
+
except (psutil.NoSuchProcess, psutil.ZombieProcess):
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _wait_for(predicate, *, timeout: float = 8.0) -> None:
|
|
58
|
+
deadline = time.monotonic() + timeout
|
|
59
|
+
while time.monotonic() < deadline:
|
|
60
|
+
if predicate():
|
|
61
|
+
return
|
|
62
|
+
time.sleep(0.01)
|
|
63
|
+
raise AssertionError("D003 fixture did not reach its handshake before timeout")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _remember(pid: int, owned: list[psutil.Process]) -> psutil.Process:
|
|
67
|
+
process = psutil.Process(pid)
|
|
68
|
+
# Prime the lifetime identity before any wait/reparent/PID-reuse race.
|
|
69
|
+
process.create_time()
|
|
70
|
+
owned.append(process)
|
|
71
|
+
return process
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _cleanup(owned: list[psutil.Process]) -> None:
|
|
75
|
+
# Test teardown uses only retained lifetime-qualified handles, never bare-PID
|
|
76
|
+
# kills, executable-name matching, or a global process sweep.
|
|
77
|
+
for process in reversed(owned):
|
|
78
|
+
try:
|
|
79
|
+
if _live(process):
|
|
80
|
+
process.kill()
|
|
81
|
+
except (psutil.NoSuchProcess, psutil.ZombieProcess):
|
|
82
|
+
pass
|
|
83
|
+
psutil.wait_procs(owned, timeout=2.0)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _collector(tmp_path: Path, *, network: bool = False) -> RuntimeCollector:
|
|
87
|
+
return RuntimeCollector(
|
|
88
|
+
session_id="d003-run",
|
|
89
|
+
sink=JsonlSink(tmp_path / "events.jsonl"),
|
|
90
|
+
watch_root=tmp_path,
|
|
91
|
+
poll_interval=0.02,
|
|
92
|
+
collect_filesystem=False,
|
|
93
|
+
collect_network=network,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _command(tmp_path: Path, exit_kind: str) -> list[str]:
|
|
98
|
+
return [
|
|
99
|
+
sys.executable, "-c", _PARENT, _CHILD,
|
|
100
|
+
str(tmp_path / "family.json"), str(tmp_path / "ready"),
|
|
101
|
+
str(tmp_path / "release"), exit_kind,
|
|
102
|
+
]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@pytest.mark.parametrize("mode", ["0", "17", "workload_exception", "collector_error", "interrupt"])
|
|
106
|
+
def test_run_finalizes_reparented_children_and_grandchildren(
|
|
107
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, mode: str,
|
|
108
|
+
) -> None:
|
|
109
|
+
collector = _collector(tmp_path)
|
|
110
|
+
owned: list[psutil.Process] = []
|
|
111
|
+
family: list[psutil.Process] = []
|
|
112
|
+
sentinel = subprocess.Popen([sys.executable, "-c", _LEAF])
|
|
113
|
+
external = _remember(sentinel.pid, owned)
|
|
114
|
+
original_sample = collector._sample_process_tree
|
|
115
|
+
root_seen = False
|
|
116
|
+
released = False
|
|
117
|
+
|
|
118
|
+
def sample(root: psutil.Process) -> None:
|
|
119
|
+
nonlocal root_seen, released
|
|
120
|
+
if not root_seen:
|
|
121
|
+
_remember(root.pid, owned)
|
|
122
|
+
root_seen = True
|
|
123
|
+
original_sample(root)
|
|
124
|
+
if released or not (tmp_path / "ready").exists():
|
|
125
|
+
return
|
|
126
|
+
pids = json.loads((tmp_path / "family.json").read_text(encoding="utf-8"))
|
|
127
|
+
if not all(pid in collector._seen_processes for pid in pids):
|
|
128
|
+
return
|
|
129
|
+
family.extend(_remember(pid, owned) for pid in pids)
|
|
130
|
+
released = True
|
|
131
|
+
(tmp_path / "release").touch()
|
|
132
|
+
_wait_for(lambda: not _live(root))
|
|
133
|
+
assert all(_live(process) for process in family)
|
|
134
|
+
if mode == "collector_error":
|
|
135
|
+
raise RuntimeError("D003 collector failure after reparent")
|
|
136
|
+
if mode == "interrupt":
|
|
137
|
+
raise KeyboardInterrupt
|
|
138
|
+
|
|
139
|
+
monkeypatch.setattr(collector, "_sample_process_tree", sample)
|
|
140
|
+
exit_kind = mode if mode in {"0", "17", "workload_exception"} else "0"
|
|
141
|
+
try:
|
|
142
|
+
if mode == "collector_error":
|
|
143
|
+
with pytest.raises(RuntimeError, match="D003 collector failure"):
|
|
144
|
+
collector.run(_command(tmp_path, exit_kind))
|
|
145
|
+
else:
|
|
146
|
+
result = collector.run(_command(tmp_path, exit_kind))
|
|
147
|
+
expected = (
|
|
148
|
+
130 if mode == "interrupt"
|
|
149
|
+
else 1 if mode == "workload_exception"
|
|
150
|
+
else int(mode)
|
|
151
|
+
)
|
|
152
|
+
assert result == expected
|
|
153
|
+
assert released and len(family) == 2
|
|
154
|
+
assert not any(_live(process) for process in family), "owned orphan survived run()"
|
|
155
|
+
assert _live(external), "unrelated same-command process was terminated"
|
|
156
|
+
events = [json.loads(line) for line in collector.sink.path.read_text().splitlines()]
|
|
157
|
+
finished = [event for event in events if event["event_type"] == "session.finished"]
|
|
158
|
+
assert len(finished) == 1
|
|
159
|
+
attributes = finished[0]["attributes"]
|
|
160
|
+
assert attributes["workload_alive_after_cleanup"] is False
|
|
161
|
+
assert attributes["collector_failed"] is (mode == "collector_error")
|
|
162
|
+
assert attributes["interrupted"] is (mode == "interrupt")
|
|
163
|
+
finally:
|
|
164
|
+
_cleanup(owned)
|
|
165
|
+
sentinel.wait(timeout=8)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_cleanup_retains_discovery_before_a_network_callback_raises(
|
|
169
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
|
|
170
|
+
) -> None:
|
|
171
|
+
collector = _collector(tmp_path, network=True)
|
|
172
|
+
owned: list[psutil.Process] = []
|
|
173
|
+
family: list[psutil.Process] = []
|
|
174
|
+
original_sample = collector._sample_process_tree
|
|
175
|
+
|
|
176
|
+
def sample(root: psutil.Process) -> None:
|
|
177
|
+
_remember(root.pid, owned)
|
|
178
|
+
_wait_for((tmp_path / "ready").exists)
|
|
179
|
+
pids = json.loads((tmp_path / "family.json").read_text(encoding="utf-8"))
|
|
180
|
+
family.extend(_remember(pid, owned) for pid in pids)
|
|
181
|
+
original_sample(root)
|
|
182
|
+
|
|
183
|
+
def fail_network(root: psutil.Process, snapshot) -> None:
|
|
184
|
+
# The tree has already been discovered, but the first callback fails
|
|
185
|
+
# before descendant process.started events have been emitted.
|
|
186
|
+
assert not any(process.pid in collector._seen_processes for process in family)
|
|
187
|
+
(tmp_path / "release").touch()
|
|
188
|
+
_wait_for(lambda: not _live(root))
|
|
189
|
+
raise RuntimeError("D003 network callback failure")
|
|
190
|
+
|
|
191
|
+
monkeypatch.setattr(collector, "_sample_process_tree", sample)
|
|
192
|
+
monkeypatch.setattr(collector, "_sample_network", fail_network)
|
|
193
|
+
try:
|
|
194
|
+
with pytest.raises(RuntimeError, match="D003 network callback failure"):
|
|
195
|
+
collector.run(_command(tmp_path, "0"))
|
|
196
|
+
assert len(family) == 2
|
|
197
|
+
assert not any(_live(process) for process in family), "discovered orphan was forgotten"
|
|
198
|
+
finished = json.loads(collector.sink.path.read_text().splitlines()[-1])
|
|
199
|
+
assert finished["attributes"]["collector_error_type"] == "RuntimeError"
|
|
200
|
+
assert finished["attributes"]["workload_alive_after_cleanup"] is False
|
|
201
|
+
assert finished["attributes"]["workload_terminated_due_to_collector_error"] is True
|
|
202
|
+
finally:
|
|
203
|
+
_cleanup(owned)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_snapshot_cleanup_needs_lifetime_not_readable_command_line(
|
|
207
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
|
|
208
|
+
) -> None:
|
|
209
|
+
collector = _collector(tmp_path)
|
|
210
|
+
snapshot = _safe_process_snapshot(psutil.Process())
|
|
211
|
+
assert snapshot is not None
|
|
212
|
+
monkeypatch.setattr(collector_module, "_safe_process_snapshot", lambda process: None)
|
|
213
|
+
matched = collector._process_for_snapshot(snapshot)
|
|
214
|
+
assert matched is not None and matched.pid == snapshot.pid
|
|
215
|
+
assert collector._process_for_snapshot(replace(snapshot, create_time=snapshot.create_time - 10)) is None
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_cleanup_is_idempotent_and_rejects_stale_process_identity(tmp_path: Path) -> None:
|
|
219
|
+
collector = _collector(tmp_path)
|
|
220
|
+
owned: list[psutil.Process] = []
|
|
221
|
+
parent = subprocess.Popen(_command(tmp_path, "0"), cwd=tmp_path)
|
|
222
|
+
root = _remember(parent.pid, owned)
|
|
223
|
+
sentinel = subprocess.Popen([sys.executable, "-c", _LEAF])
|
|
224
|
+
external = _remember(sentinel.pid, owned)
|
|
225
|
+
try:
|
|
226
|
+
_wait_for((tmp_path / "ready").exists)
|
|
227
|
+
family = [_remember(pid, owned) for pid in json.loads((tmp_path / "family.json").read_text())]
|
|
228
|
+
collector._sample_process_tree(root)
|
|
229
|
+
stale = _safe_process_snapshot(external)
|
|
230
|
+
assert stale is not None
|
|
231
|
+
collector._seen_processes[external.pid] = replace(stale, create_time=stale.create_time - 10)
|
|
232
|
+
(tmp_path / "release").touch()
|
|
233
|
+
parent.wait(timeout=8)
|
|
234
|
+
collector._terminate_process_tree(parent)
|
|
235
|
+
collector._terminate_process_tree(parent)
|
|
236
|
+
assert not any(_live(process) for process in family)
|
|
237
|
+
assert _live(external)
|
|
238
|
+
finally:
|
|
239
|
+
_cleanup(owned)
|
|
240
|
+
parent.wait(timeout=8)
|
|
241
|
+
sentinel.wait(timeout=8)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def test_interrupt_request_cleans_the_owned_tree(tmp_path: Path) -> None:
|
|
245
|
+
owned: list[psutil.Process] = []
|
|
246
|
+
env = dict(os.environ)
|
|
247
|
+
source_root = str(Path(collector_module.__file__).resolve().parents[1])
|
|
248
|
+
env["PYTHONPATH"] = os.pathsep.join(filter(None, [source_root, env.get("PYTHONPATH")]))
|
|
249
|
+
runner_code = r'''
|
|
250
|
+
import sys
|
|
251
|
+
import os
|
|
252
|
+
import time
|
|
253
|
+
import threading
|
|
254
|
+
import _thread
|
|
255
|
+
from pathlib import Path
|
|
256
|
+
from execweave.collector import RuntimeCollector
|
|
257
|
+
from execweave.sink import JsonlSink
|
|
258
|
+
root = Path(sys.argv[1])
|
|
259
|
+
collector = RuntimeCollector(
|
|
260
|
+
session_id="d003-sigint", sink=JsonlSink(root / "events.jsonl"),
|
|
261
|
+
watch_root=root, poll_interval=0.02, collect_filesystem=False, collect_network=False,
|
|
262
|
+
)
|
|
263
|
+
if os.name == "nt":
|
|
264
|
+
# Hosted Windows may not have an attached console. Trigger the real Python
|
|
265
|
+
# SIGINT handler asynchronously, not an OS console Ctrl+C acceptance claim.
|
|
266
|
+
def request_interrupt():
|
|
267
|
+
while not (root / "interrupt.requested").exists():
|
|
268
|
+
time.sleep(0.01)
|
|
269
|
+
_thread.interrupt_main()
|
|
270
|
+
threading.Thread(target=request_interrupt, daemon=True).start()
|
|
271
|
+
sys.exit(collector.run(sys.argv[2:]))
|
|
272
|
+
'''
|
|
273
|
+
runner = subprocess.Popen(
|
|
274
|
+
[sys.executable, "-c", runner_code, str(tmp_path), *_command(tmp_path, "0")],
|
|
275
|
+
env=env,
|
|
276
|
+
)
|
|
277
|
+
monitor = _remember(runner.pid, owned)
|
|
278
|
+
sentinel = subprocess.Popen([sys.executable, "-c", _LEAF])
|
|
279
|
+
external = _remember(sentinel.pid, owned)
|
|
280
|
+
try:
|
|
281
|
+
_wait_for((tmp_path / "ready").exists)
|
|
282
|
+
family = [_remember(pid, owned) for pid in json.loads((tmp_path / "family.json").read_text())]
|
|
283
|
+
roots = monitor.children()
|
|
284
|
+
assert len(roots) == 1
|
|
285
|
+
root = _remember(roots[0].pid, owned)
|
|
286
|
+
if os.name == "nt":
|
|
287
|
+
(tmp_path / "interrupt.requested").touch()
|
|
288
|
+
else:
|
|
289
|
+
runner.send_signal(signal.SIGINT)
|
|
290
|
+
assert runner.wait(timeout=15) == 130
|
|
291
|
+
assert not any(_live(process) for process in [root, *family])
|
|
292
|
+
assert _live(external)
|
|
293
|
+
finished = json.loads((tmp_path / "events.jsonl").read_text().splitlines()[-1])
|
|
294
|
+
assert finished["attributes"]["interrupted"] is True
|
|
295
|
+
assert finished["attributes"]["workload_alive_after_cleanup"] is False
|
|
296
|
+
finally:
|
|
297
|
+
_cleanup(owned)
|
|
298
|
+
runner.wait(timeout=8)
|
|
299
|
+
sentinel.wait(timeout=8)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def test_cleanup_escalates_a_survivor_after_grace_period(
|
|
303
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
|
|
304
|
+
) -> None:
|
|
305
|
+
ready = tmp_path / "ignoring-sigterm"
|
|
306
|
+
code = (
|
|
307
|
+
"import signal,time; from pathlib import Path; "
|
|
308
|
+
"signal.signal(signal.SIGTERM, signal.SIG_IGN); "
|
|
309
|
+
f"Path({str(ready)!r}).touch(); time.sleep(60)"
|
|
310
|
+
)
|
|
311
|
+
parent = subprocess.Popen([sys.executable, "-c", code])
|
|
312
|
+
owned: list[psutil.Process] = []
|
|
313
|
+
process = _remember(parent.pid, owned)
|
|
314
|
+
try:
|
|
315
|
+
_wait_for(ready.exists)
|
|
316
|
+
if os.name == "nt":
|
|
317
|
+
# Windows terminate() is already forceful. Simulate an unsuccessful
|
|
318
|
+
# first attempt, but exercise real wait/kill and identity checks.
|
|
319
|
+
original_terminate = psutil.Process.terminate
|
|
320
|
+
|
|
321
|
+
def leave_target_alive(candidate: psutil.Process) -> None:
|
|
322
|
+
if candidate != process:
|
|
323
|
+
original_terminate(candidate)
|
|
324
|
+
|
|
325
|
+
monkeypatch.setattr(psutil.Process, "terminate", leave_target_alive)
|
|
326
|
+
collector = _collector(tmp_path)
|
|
327
|
+
collector._sample_process_tree(process)
|
|
328
|
+
collector._terminate_process_tree(parent)
|
|
329
|
+
# psutil.wait_procs may reap the root before Popen.wait; do not infer
|
|
330
|
+
# its signal from Popen's ECHILD fallback return code.
|
|
331
|
+
assert not _live(process)
|
|
332
|
+
parent.wait(timeout=8)
|
|
333
|
+
collector._terminate_process_tree(parent)
|
|
334
|
+
finally:
|
|
335
|
+
_cleanup(owned)
|
|
336
|
+
parent.wait(timeout=8)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@pytest.mark.parametrize("cleanup_available", [True, False])
|
|
340
|
+
def test_cleanup_does_not_rediscover_and_lose_its_selected_processes(
|
|
341
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, cleanup_available: bool,
|
|
342
|
+
) -> None:
|
|
343
|
+
collector = _collector(tmp_path)
|
|
344
|
+
owned: list[psutil.Process] = []
|
|
345
|
+
family: list[psutil.Process] = []
|
|
346
|
+
original_owned = collector._owned_live_processes
|
|
347
|
+
released = False
|
|
348
|
+
|
|
349
|
+
def fail_sample(root: psutil.Process) -> None:
|
|
350
|
+
_remember(root.pid, owned)
|
|
351
|
+
_wait_for((tmp_path / "ready").exists)
|
|
352
|
+
pids = json.loads((tmp_path / "family.json").read_text(encoding="utf-8"))
|
|
353
|
+
family.extend(_remember(pid, owned) for pid in pids)
|
|
354
|
+
# Leave process discovery to the real cleanup routine, not the sampler.
|
|
355
|
+
raise RuntimeError("D003 failure before first sample")
|
|
356
|
+
|
|
357
|
+
def select_then_reparent(process: subprocess.Popen) -> list[psutil.Process]:
|
|
358
|
+
nonlocal released
|
|
359
|
+
selected = original_owned(process)
|
|
360
|
+
if selected and not released:
|
|
361
|
+
assert all(child in selected for child in family)
|
|
362
|
+
released = True
|
|
363
|
+
(tmp_path / "release").touch()
|
|
364
|
+
_wait_for(lambda: process.poll() is not None)
|
|
365
|
+
return selected
|
|
366
|
+
|
|
367
|
+
monkeypatch.setattr(collector, "_sample_process_tree", fail_sample)
|
|
368
|
+
monkeypatch.setattr(collector, "_owned_live_processes", select_then_reparent)
|
|
369
|
+
if not cleanup_available:
|
|
370
|
+
# Simulate denied termination: reporting must retain the selected orphan
|
|
371
|
+
# handles even when a fresh root-tree lookup can no longer find them.
|
|
372
|
+
monkeypatch.setattr(collector, "_terminate_process_tree", lambda process, *, owned: None)
|
|
373
|
+
try:
|
|
374
|
+
with pytest.raises(RuntimeError, match="D003 failure before first sample"):
|
|
375
|
+
collector.run(_command(tmp_path, "0"))
|
|
376
|
+
assert released and len(family) == 2
|
|
377
|
+
assert any(_live(child) for child in family) is (not cleanup_available)
|
|
378
|
+
finished = json.loads(collector.sink.path.read_text().splitlines()[-1])
|
|
379
|
+
assert finished["attributes"]["workload_alive_after_cleanup"] is (not cleanup_available)
|
|
380
|
+
assert finished["attributes"]["workload_terminated_due_to_collector_error"] is True
|
|
381
|
+
finally:
|
|
382
|
+
_cleanup(owned)
|
|
@@ -103,10 +103,10 @@ def test_release_version_and_noncommercial_license_metadata_are_078() -> None:
|
|
|
103
103
|
stage-integrity node-ID floor refuses renames; the assertions below are the
|
|
104
104
|
current release.
|
|
105
105
|
"""
|
|
106
|
-
assert __version__ == "0.8.
|
|
106
|
+
assert __version__ == "0.8.14"
|
|
107
107
|
pyproject = Path("pyproject.toml").read_text(encoding="utf-8")
|
|
108
|
-
assert 'version = "0.8.
|
|
109
|
-
assert "ExecWeave v0.8.
|
|
108
|
+
assert 'version = "0.8.14"' in pyproject
|
|
109
|
+
assert "ExecWeave v0.8.14 release metadata" in pyproject
|
|
110
110
|
assert "License :: Other/Proprietary License" in pyproject
|
|
111
111
|
assert "License :: OSI Approved :: MIT License" not in pyproject
|
|
112
112
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{execweave-0.8.13 → execweave-0.8.14}/.github/workflows/provider-capability-stage-integrity.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|