execweave 0.8.10__tar.gz → 0.8.11__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.10 → execweave-0.8.11}/PKG-INFO +3 -3
- {execweave-0.8.10 → execweave-0.8.11}/README.de.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/README.fr.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/README.ja.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/README.ko.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/README.md +2 -2
- {execweave-0.8.10 → execweave-0.8.11}/README.ru.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/README.zh-CN.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/README.zh-TW.md +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/pyproject.toml +2 -2
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/__init__.py +1 -1
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/auto_specialized.py +43 -8
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/collector.py +82 -22
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/strace_backend.py +4 -1
- execweave-0.8.11/tests/test_ollama_serve_runtime_integration.py +293 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v069_dashboard_release.py +3 -3
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/ci.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/cleanup-workflow-history.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/i18n.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/package-benchmark.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/package-smoke.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/provider-capability-stage-integrity.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/provider-dashboard-contract.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/publish.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/scalability.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/viewer-agent-isolation.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/wheel-smoke.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.github/workflows/windows-launcher.yml +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/.gitignore +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/LICENSE +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/benchmarks/phase1_overhead.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/antigravity-hooks.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/assets/codex.gif +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/benchmarks/README.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/benchmarks/v0.6.0-github-actions.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/benchmarks/v0.6.0-github-actions.svg +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/claude-code-hooks.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/codex-hooks.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/cursor-hooks.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/evidence-grades.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/inference-gateway.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/internal/provider-capability-matrix.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/live-graph.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/model-runtime.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/opencode-plugin.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-1-runtime-collection.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/phase-2-execution-graph.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/remaining-provider-audit-v0.8.7.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/rule-packs.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/run-integrity.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/runtime-threat-model.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/security-analysis.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.de.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.fr.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.ja.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.ko.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.ru.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.zh-CN.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/semantic-telemetry.zh-TW.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/v0.6.5-hardening-decisions.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/docs/v0.8.3-graph-ergonomics.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/audit_i18n_parity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_claude_hook.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_claude_record_graph.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_codex_hook.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_conversation_records.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_correlation_graph.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_inference_gateway_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_model_runtime_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_openai_compatible_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_release_stage_integrity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_semantic_graph.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_viewer_js.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_wheel_install.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/check_windows_launchers.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/emit_claude_hook_smoke.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/emit_codex_hook_smoke.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/emit_cursor_hook_smoke.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/emit_opencode_plugin_smoke.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/make_semantic_smoke.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/probe_provider_capability.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/scripts/sync_i18n_nav.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/__main__.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/_conversation_records_core.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/agent_bootstrap.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/agent_topology.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/agent_trace.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/agy_preview_sanitize.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/analysis.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/anthropic.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/anthropic_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/anthropic_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_adapter_base.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_full_fidelity_base.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_hook_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_subagent_linkage.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/antigravity_trace_capability.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/backends.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/benchmark.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_child_transcript.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_delegation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_hook_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_hook_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_model_observer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/claude_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_conversation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_hook_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_hook_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_message_diagnostics.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_message_transport_diagnostics.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_rollout_structures.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_rollout_trace.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/codex_rollout_trace_base.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/command.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/content_evidence.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/content_store.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_archive.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_message_identity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_antigravity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_claude.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_codex.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_common.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_generic.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_lines.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_preview_transcript.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_records.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_records_antigravity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_records_codex.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_records_common.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/conversation_records_ollama.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/correlation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_delegation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_delegation_base.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_hook_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_hook_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/cursor_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/dashboard_shell.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/entry.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/evidence_availability.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/evidence_grade.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/filesystem.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/focus.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/graph.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/graph_ops.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/http_proxy.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/http_proxy_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/inference_gateway.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/inference_gateway_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/inference_gateway_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/inference_identity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/inference_identity_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/integrity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/integrity_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/litellm_callback.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/litellm_callback_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_core.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_extra_style.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_markup.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_process_layout.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_readability.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_script_a.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_script_b.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_script_c.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_script_d.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/live_view_style.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/model_runtime.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/model_runtime_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/model_runtime_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/openai_compatible.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/openai_compatible_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/openai_compatible_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_event_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_hook_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_plugin_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/opencode_task_linkage.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/overhead_benchmark.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/provider_capability.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/provider_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/provider_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/rule_pack.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/rule_pack_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/scalability_benchmark.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/schema.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/scope.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/semantic.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/sink.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/stream_assembly.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/theme.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/top.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/top_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/validate.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/vendor/dagre.min.js +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/view_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_claude.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_codex.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_cursor.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_default.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_ollama.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_opencode.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_agent_panel_registry.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_content_inspector.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_dashboard_clean.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_dashboard_focus.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_dashboard_hardening.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_external_endpoints.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_limits.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_live_layout.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_projection.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/viewer_projection_base.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/src/execweave/workflow.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/dashboard_readability_fixture.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/codex_multi_agent/PROVENANCE.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/codex_multi_agent/hook-payloads.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/codex_multi_agent/rollout-main.jsonl +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/hooks/README.md +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/hooks/claude.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/hooks/codex.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/hooks/cursor.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/hooks/manifest.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/fixtures/hooks/opencode.json +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/multi_agent_run_fixture.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_bootstrap.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_message_viewer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_node_labels.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_said_panel.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_topology_evidence.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_trace_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agent_trace_viewer_visibility.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_agy_windows_wire_acceptance.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_analysis.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_anthropic.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_agent_collaboration.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_child_panel_policy.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_child_transcript_tools.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_cursor_launch.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_field_run_regressions.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_history_replay.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_identity_topology.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_invocation_archive.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_linkage_projection.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_multi_conversation_isolation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_official_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_role_path_fallback.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_root_child_history_v2.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_subagent_transcript_linkage.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_antigravity_trace_capability_cli.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_auto_specialized.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_backends.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_child_transcript_tools.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_delegation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_hook_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_hook_metadata.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_hook_viewer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_model_observer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_claude_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_archive_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_child_panel_policy.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_conversation_isolation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_hook_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_hook_partial_capture.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_message_diagnostics.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_message_transport_diagnostics.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_nickname_path_fallback.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_plain_routed_agent_message.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_real_multi_agent_conversation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_reducer_command.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_rollout_structures.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_rollout_trace.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_codex_routing_native_identity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_collector.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_command.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_condense.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_access.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_agent_focus.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_agent_isolation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_identity_merge.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_message_observation_dedupe.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_provider_parity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_conversation_root_authority.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_correlation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_correlation_canonical_path.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_correlation_checker.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_correlation_process_exe.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cross_provider_agent_trace.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_delegation.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_hook_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_hook_fail_open.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_ollama_session_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_cursor_task_linkage.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_dashboard_information_architecture.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_dashboard_readability_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_dashboard_round_fold_state_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_dashboard_simplification.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_dashboard_ux_and_hook_projection.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_delegation_viewer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_evidence_grade.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_execution_viewer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_external_endpoints_all_providers.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_filesystem_resilience.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_focus.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_fold_budget_setting.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_graph.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_graph_clear_focus_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_graph_edge_routing_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_graph_lane_separation_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_graph_node_sizing_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_graph_ops.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_hook_fixture_corpus.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_http_proxy.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_inference_endpoint_identity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_inference_gateway.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_inference_gateway_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_inference_identity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_integrity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_litellm_callback.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live_auth.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live_dashboard.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live_dashboard_js.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live_delta.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live_logs_export.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_live_theme.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_lmstudio_auto_specialized.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_local_runtime_live_capture.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_model_runtime.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_model_runtime_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_ollama_panel_policy.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_openai_compatible.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_adapter.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_event_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_event_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_full_fidelity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_identity_unification.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_plugin.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_record.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_opencode_task_session_linkage.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_overhead_benchmark.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_per_agent_conversation_default.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_pr25_premerge_hardening_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_pr25_premerge_hardening_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_process_tree_layout.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_provider_capability.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_provider_conversation_evidence.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_provider_conversation_history_integrity.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_provider_dashboard_contract.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_provider_lifecycle.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_release_stage_integrity_version_guard.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_rule_pack.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_schema.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_scope.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_semantic.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_shared_injected_context_scope.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_strace_backend.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_stream_assembly.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_threat_model.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_tool_traffic_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_top_detached.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v063_features.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v064_live_auto_integrations.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v064_live_evidence.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v079_review_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v079_review_regressions.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_v083_release_gate_p2.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_validate.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_version.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_viewer.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_viewer_agent_isolation_e2e.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_viewer_child_authority.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_viewer_content_inspector.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_viewer_limits.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_viewer_projection.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_windows_codex_agy_display_repair.py +0 -0
- {execweave-0.8.10 → execweave-0.8.11}/tests/test_workflow.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.11
|
|
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
|
|
@@ -85,7 +85,7 @@ ExecWeave is a source-available, local-first observability project that turns AI
|
|
|
85
85
|
<img src="docs/assets/codex.gif" alt="ExecWeave animated live demo" width="100%">
|
|
86
86
|
</p>
|
|
87
87
|
|
|
88
|
-
This README documents **v0.8.
|
|
88
|
+
This README documents **v0.8.11**. This release makes managed local `ollama serve` capture fail-safe for independent loopback clients, so a later `ollama run`, SDK, or `curl` request from another terminal is recorded in the same semantic stream instead of silently falling back without conversation evidence. It also finalizes merged events, `graph.json`, and `viewer.html` when a Live run is stopped with Ctrl+C.
|
|
89
89
|
|
|
90
90
|
## Why ExecWeave
|
|
91
91
|
|
|
@@ -130,7 +130,7 @@ Google Antigravity currently uses the `agy` CLI command; ExecWeave also accepts
|
|
|
130
130
|
|
|
131
131
|
For Cursor on Windows, bare `cursor` follows the PATH entry the user actually has and, when it is the normal `.../resources/app/bin/cursor.cmd` shim, derives the matching `Cursor.exe` from that same installation root. This works for custom drives and arbitrary install directories; explicit launcher paths are left untouched. macOS/Windows standard desktop paths remain a fallback when the PATH shim cannot identify the desktop binary.
|
|
132
132
|
|
|
133
|
-
For a managed local Ollama server, `execweave live --open -- ollama serve` owns the public loopback endpoint and relays the real server through an internal loopback port. A later `ollama run`, Ollama SDK request, OpenAI-compatible client, or `curl` started from another terminal can therefore appear in the same ExecWeave semantic stream even though that client is not a child of the `ollama serve` process. Relay mode is deliberately limited to local `localhost` / `127.0.0.1` binds; external, wildcard, and IPv6 exposure is not rewritten.
|
|
133
|
+
For a managed local Ollama server, `execweave live --open -- ollama serve` owns the public loopback endpoint and relays the real server through an internal loopback port. A later `ollama run`, Ollama SDK request, OpenAI-compatible client, or `curl` started from another terminal can therefore appear in the same ExecWeave semantic stream even though that client is not a child of the `ollama serve` process. ExecWeave prints the active public-to-internal relay mapping; if the public loopback endpoint cannot be safely reserved, the managed run now fails explicitly rather than silently losing conversation capture. Relay mode is deliberately limited to local `localhost` / `127.0.0.1` binds; external, wildcard, and IPv6 exposure is not rewritten. Stopping Live with Ctrl+C still finalizes the run artifacts before returning.
|
|
134
134
|
|
|
135
135
|
Build finalized run artifacts with:
|
|
136
136
|
|
|
@@ -32,7 +32,7 @@ ExecWeave ist ein source-available, local-first Observability-Projekt, das Aktiv
|
|
|
32
32
|
<img src="docs/assets/codex.gif" alt="ExecWeave animated live demo" width="100%">
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
Dieses README dokumentiert **v0.8.
|
|
35
|
+
Dieses README dokumentiert **v0.8.11**.
|
|
36
36
|
|
|
37
37
|
## Warum ExecWeave
|
|
38
38
|
|
|
@@ -32,7 +32,7 @@ ExecWeave est un projet d’observabilité source-available et local-first qui t
|
|
|
32
32
|
<img src="docs/assets/codex.gif" alt="ExecWeave animated live demo" width="100%">
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
Ce README décrit **v0.8.
|
|
35
|
+
Ce README décrit **v0.8.11**.
|
|
36
36
|
|
|
37
37
|
## Pourquoi ExecWeave
|
|
38
38
|
|
|
@@ -32,7 +32,7 @@ ExecWeave is a source-available, local-first observability project that turns AI
|
|
|
32
32
|
<img src="docs/assets/codex.gif" alt="ExecWeave animated live demo" width="100%">
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
This README documents **v0.8.
|
|
35
|
+
This README documents **v0.8.11**. This release makes managed local `ollama serve` capture fail-safe for independent loopback clients, so a later `ollama run`, SDK, or `curl` request from another terminal is recorded in the same semantic stream instead of silently falling back without conversation evidence. It also finalizes merged events, `graph.json`, and `viewer.html` when a Live run is stopped with Ctrl+C.
|
|
36
36
|
|
|
37
37
|
## Why ExecWeave
|
|
38
38
|
|
|
@@ -77,7 +77,7 @@ Google Antigravity currently uses the `agy` CLI command; ExecWeave also accepts
|
|
|
77
77
|
|
|
78
78
|
For Cursor on Windows, bare `cursor` follows the PATH entry the user actually has and, when it is the normal `.../resources/app/bin/cursor.cmd` shim, derives the matching `Cursor.exe` from that same installation root. This works for custom drives and arbitrary install directories; explicit launcher paths are left untouched. macOS/Windows standard desktop paths remain a fallback when the PATH shim cannot identify the desktop binary.
|
|
79
79
|
|
|
80
|
-
For a managed local Ollama server, `execweave live --open -- ollama serve` owns the public loopback endpoint and relays the real server through an internal loopback port. A later `ollama run`, Ollama SDK request, OpenAI-compatible client, or `curl` started from another terminal can therefore appear in the same ExecWeave semantic stream even though that client is not a child of the `ollama serve` process. Relay mode is deliberately limited to local `localhost` / `127.0.0.1` binds; external, wildcard, and IPv6 exposure is not rewritten.
|
|
80
|
+
For a managed local Ollama server, `execweave live --open -- ollama serve` owns the public loopback endpoint and relays the real server through an internal loopback port. A later `ollama run`, Ollama SDK request, OpenAI-compatible client, or `curl` started from another terminal can therefore appear in the same ExecWeave semantic stream even though that client is not a child of the `ollama serve` process. ExecWeave prints the active public-to-internal relay mapping; if the public loopback endpoint cannot be safely reserved, the managed run now fails explicitly rather than silently losing conversation capture. Relay mode is deliberately limited to local `localhost` / `127.0.0.1` binds; external, wildcard, and IPv6 exposure is not rewritten. Stopping Live with Ctrl+C still finalizes the run artifacts before returning.
|
|
81
81
|
|
|
82
82
|
Build finalized run artifacts with:
|
|
83
83
|
|
|
@@ -32,7 +32,7 @@ ExecWeave — source-available, local-first проект наблюдаемос
|
|
|
32
32
|
<img src="docs/assets/codex.gif" alt="ExecWeave animated live demo" width="100%">
|
|
33
33
|
</p>
|
|
34
34
|
|
|
35
|
-
Этот README описывает **v0.8.
|
|
35
|
+
Этот README описывает **v0.8.11**.
|
|
36
36
|
|
|
37
37
|
## Почему ExecWeave
|
|
38
38
|
|
|
@@ -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.11 release metadata
|
|
8
|
+
version = "0.8.11"
|
|
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"
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
5
|
import socket
|
|
6
|
+
import sys
|
|
6
7
|
import threading
|
|
7
8
|
import time
|
|
8
9
|
from contextlib import contextmanager
|
|
@@ -398,18 +399,47 @@ def auto_specialized_launch(
|
|
|
398
399
|
yield environment
|
|
399
400
|
return
|
|
400
401
|
listen_host, listen_port = listen_address
|
|
401
|
-
|
|
402
|
-
upstream = f"http://127.0.0.1:{internal_port}"
|
|
402
|
+
public_endpoint = f"http://{listen_host}:{listen_port}"
|
|
403
403
|
try:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
404
|
+
existing = _get_json(
|
|
405
|
+
f"{public_endpoint}/api/ps",
|
|
406
|
+
timeout=_PROBE_TIMEOUT_SECONDS,
|
|
407
|
+
)
|
|
408
|
+
except _PROBE_ERRORS:
|
|
409
|
+
existing = None
|
|
410
|
+
if isinstance(existing, dict) and isinstance(existing.get("models"), list):
|
|
411
|
+
print(
|
|
412
|
+
"ExecWeave Ollama relay: existing Ollama server detected at "
|
|
413
|
+
f"{public_endpoint}; leaving that server unclaimed.",
|
|
414
|
+
file=sys.stderr,
|
|
408
415
|
)
|
|
409
|
-
except OSError:
|
|
410
|
-
# Fail open: preserve the child command's normal bind/error behavior.
|
|
411
416
|
yield environment
|
|
412
417
|
return
|
|
418
|
+
|
|
419
|
+
internal_port = _allocate_loopback_port()
|
|
420
|
+
upstream = f"http://127.0.0.1:{internal_port}"
|
|
421
|
+
server: ExecWeaveHTTPProxyServer | None = None
|
|
422
|
+
last_bind_error: OSError | None = None
|
|
423
|
+
for attempt in range(5):
|
|
424
|
+
try:
|
|
425
|
+
server = ExecWeaveHTTPProxyServer(
|
|
426
|
+
(listen_host, listen_port),
|
|
427
|
+
ProxyConfig(upstream=upstream, sidecar=sidecar, mode="ollama"),
|
|
428
|
+
recorder=_record_ollama_inference_exchange,
|
|
429
|
+
)
|
|
430
|
+
break
|
|
431
|
+
except OSError as exc:
|
|
432
|
+
last_bind_error = exc
|
|
433
|
+
if attempt < 4:
|
|
434
|
+
time.sleep(0.05)
|
|
435
|
+
if server is None:
|
|
436
|
+
raise RuntimeError(
|
|
437
|
+
"ExecWeave could not reserve the Ollama endpoint "
|
|
438
|
+
f"{public_endpoint} for transparent conversation capture. "
|
|
439
|
+
"Stop any existing Ollama server using that endpoint or set "
|
|
440
|
+
"OLLAMA_HOST to a free loopback port before starting "
|
|
441
|
+
"`execweave live -- ollama serve`."
|
|
442
|
+
) from last_bind_error
|
|
413
443
|
thread = threading.Thread(
|
|
414
444
|
target=server.serve_forever,
|
|
415
445
|
kwargs={"poll_interval": 0.05},
|
|
@@ -418,6 +448,11 @@ def auto_specialized_launch(
|
|
|
418
448
|
)
|
|
419
449
|
thread.start()
|
|
420
450
|
environment["OLLAMA_HOST"] = upstream
|
|
451
|
+
print(
|
|
452
|
+
"ExecWeave Ollama relay: "
|
|
453
|
+
f"http://{listen_host}:{listen_port} -> {upstream}",
|
|
454
|
+
file=sys.stderr,
|
|
455
|
+
)
|
|
421
456
|
try:
|
|
422
457
|
yield environment
|
|
423
458
|
finally:
|
|
@@ -9,6 +9,7 @@ from typing import Iterable
|
|
|
9
9
|
|
|
10
10
|
import psutil
|
|
11
11
|
|
|
12
|
+
from . import __version__
|
|
12
13
|
from .auto_specialized import (
|
|
13
14
|
auto_specialized_launch,
|
|
14
15
|
auto_specialized_probe,
|
|
@@ -139,6 +140,7 @@ class RuntimeCollector:
|
|
|
139
140
|
"command": command,
|
|
140
141
|
"cwd": str(self.watch_root),
|
|
141
142
|
"backend": self.backend_name,
|
|
143
|
+
"execweave_version": __version__,
|
|
142
144
|
},
|
|
143
145
|
)
|
|
144
146
|
self.sink.emit(
|
|
@@ -148,7 +150,11 @@ class RuntimeCollector:
|
|
|
148
150
|
relation="STARTED_SESSION",
|
|
149
151
|
source=agent,
|
|
150
152
|
target=session,
|
|
151
|
-
attributes={
|
|
153
|
+
attributes={
|
|
154
|
+
"collector_pid": os.getpid(),
|
|
155
|
+
"backend": self.backend_name,
|
|
156
|
+
"execweave_version": __version__,
|
|
157
|
+
},
|
|
152
158
|
)
|
|
153
159
|
)
|
|
154
160
|
|
|
@@ -166,31 +172,42 @@ class RuntimeCollector:
|
|
|
166
172
|
|
|
167
173
|
process: subprocess.Popen[bytes] | None = None
|
|
168
174
|
return_code = 1
|
|
175
|
+
interrupted = False
|
|
169
176
|
post_command_probe = prepare_post_command_specialized_probe(command)
|
|
170
177
|
try:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
try:
|
|
179
|
+
with auto_specialized_launch(
|
|
180
|
+
command,
|
|
181
|
+
server_relay=True,
|
|
182
|
+
) as launch_environment:
|
|
183
|
+
process = subprocess.Popen(
|
|
184
|
+
launch_command,
|
|
185
|
+
cwd=str(self.watch_root),
|
|
186
|
+
env=launch_environment,
|
|
187
|
+
)
|
|
188
|
+
root = psutil.Process(process.pid)
|
|
189
|
+
snapshot = _safe_process_snapshot(root)
|
|
190
|
+
if snapshot is not None:
|
|
191
|
+
self._record_process_start(snapshot, parent=session, relation="LAUNCHED")
|
|
192
|
+
|
|
193
|
+
with auto_specialized_probe(command):
|
|
194
|
+
while process.poll() is None:
|
|
195
|
+
self._sample_process_tree(root)
|
|
196
|
+
time.sleep(self.poll_interval)
|
|
181
197
|
|
|
182
|
-
with auto_specialized_probe(command):
|
|
183
|
-
while process.poll() is None:
|
|
184
198
|
self._sample_process_tree(root)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return_code =
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
199
|
+
self._mark_disappeared_processes(set())
|
|
200
|
+
return_code = int(process.returncode or 0)
|
|
201
|
+
except KeyboardInterrupt:
|
|
202
|
+
interrupted = True
|
|
203
|
+
return_code = 130
|
|
204
|
+
if process is not None:
|
|
205
|
+
self._terminate_process_tree(process)
|
|
206
|
+
if not interrupted:
|
|
207
|
+
run_post_command_specialized_probe(
|
|
208
|
+
post_command_probe,
|
|
209
|
+
return_code=return_code,
|
|
210
|
+
)
|
|
194
211
|
return return_code
|
|
195
212
|
finally:
|
|
196
213
|
if watcher is not None:
|
|
@@ -205,10 +222,53 @@ class RuntimeCollector:
|
|
|
205
222
|
"return_code": return_code,
|
|
206
223
|
"root_pid": process.pid if process is not None else None,
|
|
207
224
|
"backend": self.backend_name,
|
|
225
|
+
"interrupted": interrupted,
|
|
226
|
+
"execweave_version": __version__,
|
|
208
227
|
},
|
|
209
228
|
)
|
|
210
229
|
)
|
|
211
230
|
|
|
231
|
+
@staticmethod
|
|
232
|
+
def _terminate_process_tree(process: subprocess.Popen[bytes]) -> None:
|
|
233
|
+
descendants: list[psutil.Process] = []
|
|
234
|
+
try:
|
|
235
|
+
root = psutil.Process(process.pid)
|
|
236
|
+
descendants = root.children(recursive=True)
|
|
237
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
238
|
+
pass
|
|
239
|
+
|
|
240
|
+
for child in reversed(descendants):
|
|
241
|
+
try:
|
|
242
|
+
child.terminate()
|
|
243
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
244
|
+
pass
|
|
245
|
+
|
|
246
|
+
if process.poll() is None:
|
|
247
|
+
try:
|
|
248
|
+
process.terminate()
|
|
249
|
+
except OSError:
|
|
250
|
+
pass
|
|
251
|
+
|
|
252
|
+
if descendants:
|
|
253
|
+
_, alive = psutil.wait_procs(descendants, timeout=2.0)
|
|
254
|
+
for child in alive:
|
|
255
|
+
try:
|
|
256
|
+
child.kill()
|
|
257
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
|
|
258
|
+
pass
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
process.wait(timeout=2.0)
|
|
262
|
+
except subprocess.TimeoutExpired:
|
|
263
|
+
try:
|
|
264
|
+
process.kill()
|
|
265
|
+
except OSError:
|
|
266
|
+
return
|
|
267
|
+
try:
|
|
268
|
+
process.wait(timeout=2.0)
|
|
269
|
+
except subprocess.TimeoutExpired:
|
|
270
|
+
pass
|
|
271
|
+
|
|
212
272
|
def _sample_process_tree(self, root: psutil.Process) -> None:
|
|
213
273
|
processes: list[psutil.Process] = []
|
|
214
274
|
try:
|
|
@@ -653,7 +653,10 @@ class StraceRuntimeCollector:
|
|
|
653
653
|
]
|
|
654
654
|
return_code = 1
|
|
655
655
|
try:
|
|
656
|
-
with auto_specialized_launch(
|
|
656
|
+
with auto_specialized_launch(
|
|
657
|
+
command,
|
|
658
|
+
server_relay=True,
|
|
659
|
+
) as launch_environment:
|
|
657
660
|
completed = subprocess.run(
|
|
658
661
|
strace_command,
|
|
659
662
|
cwd=str(self.watch_root),
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import socket
|
|
5
|
+
import sys
|
|
6
|
+
import threading
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from urllib.error import URLError
|
|
10
|
+
from urllib.request import Request, urlopen
|
|
11
|
+
|
|
12
|
+
import psutil
|
|
13
|
+
import pytest
|
|
14
|
+
|
|
15
|
+
import execweave
|
|
16
|
+
import execweave.collector as collector_module
|
|
17
|
+
from execweave.auto_specialized import auto_specialized_launch
|
|
18
|
+
from execweave.collector import RuntimeCollector
|
|
19
|
+
from execweave.live_core import run_live
|
|
20
|
+
from execweave.sink import JsonlSink
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _free_loopback_port() -> int:
|
|
24
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
25
|
+
sock.bind(("127.0.0.1", 0))
|
|
26
|
+
return int(sock.getsockname()[1])
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _wait_for_json(url: str, timeout: float = 8.0) -> dict[str, object]:
|
|
30
|
+
deadline = time.monotonic() + timeout
|
|
31
|
+
last_error: Exception | None = None
|
|
32
|
+
while time.monotonic() < deadline:
|
|
33
|
+
try:
|
|
34
|
+
with urlopen(url, timeout=0.5) as response:
|
|
35
|
+
value = json.loads(response.read().decode("utf-8"))
|
|
36
|
+
if isinstance(value, dict):
|
|
37
|
+
return value
|
|
38
|
+
except (URLError, OSError, TimeoutError, json.JSONDecodeError) as exc:
|
|
39
|
+
last_error = exc
|
|
40
|
+
time.sleep(0.05)
|
|
41
|
+
raise AssertionError(f"endpoint did not become ready: {url}: {last_error}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _wait_for_child_ready(
|
|
45
|
+
ready_path: Path,
|
|
46
|
+
*,
|
|
47
|
+
started_path: Path,
|
|
48
|
+
thread: threading.Thread,
|
|
49
|
+
errors: list[BaseException],
|
|
50
|
+
result: dict[str, object],
|
|
51
|
+
event_path: Path,
|
|
52
|
+
timeout: float = 8.0,
|
|
53
|
+
) -> None:
|
|
54
|
+
deadline = time.monotonic() + timeout
|
|
55
|
+
while time.monotonic() < deadline:
|
|
56
|
+
if ready_path.exists():
|
|
57
|
+
return
|
|
58
|
+
if errors or not thread.is_alive():
|
|
59
|
+
events = event_path.read_text(encoding="utf-8") if event_path.exists() else ""
|
|
60
|
+
raise AssertionError(
|
|
61
|
+
"collector stopped before fake Ollama became ready: "
|
|
62
|
+
f"started={started_path.exists()} errors={errors!r} "
|
|
63
|
+
f"result={result!r} events={events}"
|
|
64
|
+
)
|
|
65
|
+
time.sleep(0.02)
|
|
66
|
+
events = event_path.read_text(encoding="utf-8") if event_path.exists() else ""
|
|
67
|
+
raise AssertionError(
|
|
68
|
+
"fake Ollama did not become ready: "
|
|
69
|
+
f"started={started_path.exists()} thread_alive={thread.is_alive()} "
|
|
70
|
+
f"errors={errors!r} result={result!r} events={events}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _write_fake_ollama_server(path: Path) -> None:
|
|
75
|
+
path.write_text(
|
|
76
|
+
r'''from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
77
|
+
import json
|
|
78
|
+
import os
|
|
79
|
+
from pathlib import Path
|
|
80
|
+
import socket
|
|
81
|
+
from urllib.parse import urlsplit
|
|
82
|
+
|
|
83
|
+
Path(os.environ["FAKE_OLLAMA_STARTED"]).write_text("started", encoding="utf-8")
|
|
84
|
+
endpoint = urlsplit(os.environ["OLLAMA_HOST"])
|
|
85
|
+
|
|
86
|
+
# HTTPServer.server_bind() calls socket.getfqdn(). On GitHub's macOS runner
|
|
87
|
+
# that lookup can block for many seconds even for a loopback address, which
|
|
88
|
+
# makes this local fixture race the test timeout. Avoid external hostname
|
|
89
|
+
# resolution: this fixture only needs an HTTP listener on a known loopback IP.
|
|
90
|
+
socket.getfqdn = lambda name="": name or "127.0.0.1"
|
|
91
|
+
|
|
92
|
+
class Handler(BaseHTTPRequestHandler):
|
|
93
|
+
def log_message(self, format, *args):
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
def send_json(self, payload, status=200):
|
|
97
|
+
body = json.dumps(payload).encode("utf-8")
|
|
98
|
+
self.send_response(status)
|
|
99
|
+
self.send_header("Content-Type", "application/json")
|
|
100
|
+
self.send_header("Content-Length", str(len(body)))
|
|
101
|
+
self.end_headers()
|
|
102
|
+
self.wfile.write(body)
|
|
103
|
+
|
|
104
|
+
def do_GET(self):
|
|
105
|
+
if self.path == "/api/ps":
|
|
106
|
+
self.send_json({"models": []})
|
|
107
|
+
return
|
|
108
|
+
self.send_json({"error": "not found"}, 404)
|
|
109
|
+
|
|
110
|
+
def do_POST(self):
|
|
111
|
+
length = int(self.headers.get("Content-Length", "0"))
|
|
112
|
+
request = json.loads(self.rfile.read(length).decode("utf-8"))
|
|
113
|
+
if self.path != "/api/chat":
|
|
114
|
+
self.send_json({"error": "not found"}, 404)
|
|
115
|
+
return
|
|
116
|
+
self.send_json({
|
|
117
|
+
"model": request.get("model", "tiny"),
|
|
118
|
+
"message": {"role": "assistant", "content": "collector relay answer"},
|
|
119
|
+
"done": True,
|
|
120
|
+
})
|
|
121
|
+
self.server.done = True
|
|
122
|
+
|
|
123
|
+
server = HTTPServer((endpoint.hostname, endpoint.port), Handler)
|
|
124
|
+
server.timeout = 0.2
|
|
125
|
+
server.done = False
|
|
126
|
+
Path(os.environ["FAKE_OLLAMA_READY"]).write_text("ready", encoding="utf-8")
|
|
127
|
+
while not server.done:
|
|
128
|
+
server.handle_request()
|
|
129
|
+
server.server_close()
|
|
130
|
+
''',
|
|
131
|
+
encoding="utf-8",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_runtime_collector_ollama_serve_captures_independent_client(
|
|
136
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
137
|
+
tmp_path: Path,
|
|
138
|
+
) -> None:
|
|
139
|
+
public_port = _free_loopback_port()
|
|
140
|
+
public_endpoint = f"http://127.0.0.1:{public_port}"
|
|
141
|
+
sidecar = tmp_path / "semantic.jsonl"
|
|
142
|
+
event_path = tmp_path / "events.jsonl"
|
|
143
|
+
started_path = tmp_path / "fake-ollama.started"
|
|
144
|
+
ready_path = tmp_path / "fake-ollama.ready"
|
|
145
|
+
fake_server = tmp_path / "fake_ollama_server.py"
|
|
146
|
+
_write_fake_ollama_server(fake_server)
|
|
147
|
+
|
|
148
|
+
monkeypatch.setenv("EXECWEAVE_SEMANTIC_SIDECAR", str(sidecar))
|
|
149
|
+
monkeypatch.setenv("OLLAMA_HOST", public_endpoint)
|
|
150
|
+
monkeypatch.setenv("FAKE_OLLAMA_STARTED", str(started_path))
|
|
151
|
+
monkeypatch.setenv("FAKE_OLLAMA_READY", str(ready_path))
|
|
152
|
+
monkeypatch.setattr(
|
|
153
|
+
collector_module,
|
|
154
|
+
"resolve_launch_command",
|
|
155
|
+
lambda command: [sys.executable, str(fake_server)],
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
collector = RuntimeCollector(
|
|
159
|
+
session_id="serve-integration",
|
|
160
|
+
sink=JsonlSink(event_path),
|
|
161
|
+
watch_root=tmp_path,
|
|
162
|
+
poll_interval=0.02,
|
|
163
|
+
collect_filesystem=False,
|
|
164
|
+
collect_network=False,
|
|
165
|
+
)
|
|
166
|
+
result: dict[str, object] = {}
|
|
167
|
+
errors: list[BaseException] = []
|
|
168
|
+
|
|
169
|
+
def run_collector() -> None:
|
|
170
|
+
try:
|
|
171
|
+
result["return_code"] = collector.run(["ollama", "serve"])
|
|
172
|
+
except BaseException as exc:
|
|
173
|
+
errors.append(exc)
|
|
174
|
+
|
|
175
|
+
thread = threading.Thread(target=run_collector, daemon=True)
|
|
176
|
+
thread.start()
|
|
177
|
+
|
|
178
|
+
_wait_for_child_ready(
|
|
179
|
+
ready_path,
|
|
180
|
+
started_path=started_path,
|
|
181
|
+
thread=thread,
|
|
182
|
+
errors=errors,
|
|
183
|
+
result=result,
|
|
184
|
+
event_path=event_path,
|
|
185
|
+
)
|
|
186
|
+
assert _wait_for_json(public_endpoint + "/api/ps") == {"models": []}
|
|
187
|
+
|
|
188
|
+
request = Request(
|
|
189
|
+
public_endpoint + "/api/chat",
|
|
190
|
+
data=json.dumps(
|
|
191
|
+
{
|
|
192
|
+
"model": "tiny",
|
|
193
|
+
"messages": [{"role": "user", "content": "outside process tree"}],
|
|
194
|
+
}
|
|
195
|
+
).encode("utf-8"),
|
|
196
|
+
headers={"Content-Type": "application/json"},
|
|
197
|
+
method="POST",
|
|
198
|
+
)
|
|
199
|
+
with urlopen(request, timeout=5) as response:
|
|
200
|
+
response_payload = json.loads(response.read().decode("utf-8"))
|
|
201
|
+
assert response_payload["message"]["content"] == "collector relay answer"
|
|
202
|
+
|
|
203
|
+
thread.join(timeout=10)
|
|
204
|
+
assert not thread.is_alive()
|
|
205
|
+
assert errors == []
|
|
206
|
+
assert result["return_code"] == 0
|
|
207
|
+
|
|
208
|
+
semantic_rows = [
|
|
209
|
+
json.loads(line)
|
|
210
|
+
for line in sidecar.read_text(encoding="utf-8").splitlines()
|
|
211
|
+
if line.strip()
|
|
212
|
+
]
|
|
213
|
+
kinds = {
|
|
214
|
+
(row.get("target", {}).get("attributes") or {}).get("content_kind")
|
|
215
|
+
for row in semantic_rows
|
|
216
|
+
if isinstance(row, dict)
|
|
217
|
+
}
|
|
218
|
+
assert "model_runtime.ollama.request_messages" in kinds
|
|
219
|
+
assert "model_runtime.ollama.assistant_messages" in kinds
|
|
220
|
+
assert any(
|
|
221
|
+
row.get("attributes", {}).get("transport_relay_observed") is True
|
|
222
|
+
for row in semantic_rows
|
|
223
|
+
if isinstance(row, dict)
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
runtime_rows = [
|
|
227
|
+
json.loads(line)
|
|
228
|
+
for line in event_path.read_text(encoding="utf-8").splitlines()
|
|
229
|
+
if line.strip()
|
|
230
|
+
]
|
|
231
|
+
started = next(row for row in runtime_rows if row["event_type"] == "session.started")
|
|
232
|
+
assert started["attributes"]["execweave_version"] == execweave.__version__
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def test_ollama_serve_relay_bind_failure_is_not_silent(
|
|
236
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
237
|
+
tmp_path: Path,
|
|
238
|
+
) -> None:
|
|
239
|
+
# A raw TCP listener is intentionally not an Ollama server: the /api/ps
|
|
240
|
+
# preflight must not classify arbitrary port occupancy as a server to preserve.
|
|
241
|
+
holder = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
242
|
+
holder.bind(("127.0.0.1", 0))
|
|
243
|
+
holder.listen()
|
|
244
|
+
port = int(holder.getsockname()[1])
|
|
245
|
+
monkeypatch.setenv("EXECWEAVE_SEMANTIC_SIDECAR", str(tmp_path / "semantic.jsonl"))
|
|
246
|
+
monkeypatch.setenv("OLLAMA_HOST", f"http://127.0.0.1:{port}")
|
|
247
|
+
try:
|
|
248
|
+
with pytest.raises(RuntimeError, match="could not reserve the Ollama endpoint"):
|
|
249
|
+
with auto_specialized_launch(
|
|
250
|
+
["ollama", "serve"],
|
|
251
|
+
server_relay=True,
|
|
252
|
+
):
|
|
253
|
+
raise AssertionError("relay must not silently fall back")
|
|
254
|
+
finally:
|
|
255
|
+
holder.close()
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def test_ctrl_c_still_materializes_live_artifacts(
|
|
259
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
260
|
+
tmp_path: Path,
|
|
261
|
+
) -> None:
|
|
262
|
+
def interrupt_poll(self: RuntimeCollector, root: psutil.Process) -> None:
|
|
263
|
+
raise KeyboardInterrupt
|
|
264
|
+
|
|
265
|
+
monkeypatch.setattr(RuntimeCollector, "_sample_process_tree", interrupt_poll)
|
|
266
|
+
result = run_live(
|
|
267
|
+
[sys.executable, "-c", "import time; time.sleep(30)"],
|
|
268
|
+
watch_root=tmp_path,
|
|
269
|
+
output_dir=tmp_path / "run",
|
|
270
|
+
collect_filesystem=False,
|
|
271
|
+
collect_network=False,
|
|
272
|
+
open_browser=False,
|
|
273
|
+
linger_seconds=0,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
assert result.return_code == 130
|
|
277
|
+
assert result.graph.exists()
|
|
278
|
+
assert result.viewer.exists()
|
|
279
|
+
assert result.materialized_event_stream.exists()
|
|
280
|
+
|
|
281
|
+
rows = [
|
|
282
|
+
json.loads(line)
|
|
283
|
+
for line in result.event_stream.read_text(encoding="utf-8").splitlines()
|
|
284
|
+
if line.strip()
|
|
285
|
+
]
|
|
286
|
+
finished = next(row for row in rows if row["event_type"] == "session.finished")
|
|
287
|
+
assert finished["attributes"]["return_code"] == 130
|
|
288
|
+
assert finished["attributes"]["interrupted"] is True
|
|
289
|
+
assert finished["attributes"]["execweave_version"] == execweave.__version__
|
|
290
|
+
|
|
291
|
+
launched = next(row for row in rows if row["event_type"] == "process.started")
|
|
292
|
+
pid = int(launched["target"]["attributes"]["pid"])
|
|
293
|
+
assert not psutil.pid_exists(pid)
|