execweave 0.8.12__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.
Files changed (583) hide show
  1. {execweave-0.8.12 → execweave-0.8.14}/PKG-INFO +1 -1
  2. {execweave-0.8.12 → execweave-0.8.14}/pyproject.toml +2 -2
  3. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/__init__.py +1 -1
  4. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/collector.py +120 -24
  5. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/command.py +6 -1
  6. execweave-0.8.14/tests/test_pypi_0812_regressions.py +171 -0
  7. execweave-0.8.14/tests/test_pypi_0813_cleanup.py +382 -0
  8. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v069_dashboard_release.py +3 -3
  9. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/ci.yml +0 -0
  10. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/cleanup-workflow-history.yml +0 -0
  11. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/i18n.yml +0 -0
  12. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/package-benchmark.yml +0 -0
  13. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/package-smoke.yml +0 -0
  14. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/provider-capability-stage-integrity.yml +0 -0
  15. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/provider-dashboard-contract.yml +0 -0
  16. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/publish.yml +0 -0
  17. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/scalability.yml +0 -0
  18. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/viewer-agent-isolation.yml +0 -0
  19. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/wheel-smoke.yml +0 -0
  20. {execweave-0.8.12 → execweave-0.8.14}/.github/workflows/windows-launcher.yml +0 -0
  21. {execweave-0.8.12 → execweave-0.8.14}/.gitignore +0 -0
  22. {execweave-0.8.12 → execweave-0.8.14}/LICENSE +0 -0
  23. {execweave-0.8.12 → execweave-0.8.14}/README.de.md +0 -0
  24. {execweave-0.8.12 → execweave-0.8.14}/README.fr.md +0 -0
  25. {execweave-0.8.12 → execweave-0.8.14}/README.ja.md +0 -0
  26. {execweave-0.8.12 → execweave-0.8.14}/README.ko.md +0 -0
  27. {execweave-0.8.12 → execweave-0.8.14}/README.md +0 -0
  28. {execweave-0.8.12 → execweave-0.8.14}/README.ru.md +0 -0
  29. {execweave-0.8.12 → execweave-0.8.14}/README.zh-CN.md +0 -0
  30. {execweave-0.8.12 → execweave-0.8.14}/README.zh-TW.md +0 -0
  31. {execweave-0.8.12 → execweave-0.8.14}/benchmarks/phase1_overhead.py +0 -0
  32. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/acceptance_hardening_20260906.md +0 -0
  33. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/audit_eight_children.py +0 -0
  34. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/audit_python_journey.py +0 -0
  35. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/audit_real_clicks.py +0 -0
  36. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/current_state_reaudit.md +0 -0
  37. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/execweave_full_audit.md +0 -0
  38. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/gate_status.md +0 -0
  39. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/gate_status_history_through_g3.md +0 -0
  40. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/github_pr_inventory.json +0 -0
  41. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/handoff_checkpoint_20260906.md +0 -0
  42. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/next_agent_handoff.md +0 -0
  43. {execweave-0.8.12 → execweave-0.8.14}/diagnostics/pr_regression_map.md +0 -0
  44. {execweave-0.8.12 → execweave-0.8.14}/docs/antigravity-hooks.md +0 -0
  45. {execweave-0.8.12 → execweave-0.8.14}/docs/assets/codex.gif +0 -0
  46. {execweave-0.8.12 → execweave-0.8.14}/docs/benchmarks/README.md +0 -0
  47. {execweave-0.8.12 → execweave-0.8.14}/docs/benchmarks/v0.6.0-github-actions.json +0 -0
  48. {execweave-0.8.12 → execweave-0.8.14}/docs/benchmarks/v0.6.0-github-actions.svg +0 -0
  49. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.de.md +0 -0
  50. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.fr.md +0 -0
  51. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.ja.md +0 -0
  52. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.ko.md +0 -0
  53. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.md +0 -0
  54. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.ru.md +0 -0
  55. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.zh-CN.md +0 -0
  56. {execweave-0.8.12 → execweave-0.8.14}/docs/claude-code-hooks.zh-TW.md +0 -0
  57. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.de.md +0 -0
  58. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.fr.md +0 -0
  59. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.ja.md +0 -0
  60. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.ko.md +0 -0
  61. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.md +0 -0
  62. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.ru.md +0 -0
  63. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.zh-CN.md +0 -0
  64. {execweave-0.8.12 → execweave-0.8.14}/docs/codex-hooks.zh-TW.md +0 -0
  65. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.de.md +0 -0
  66. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.fr.md +0 -0
  67. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.ja.md +0 -0
  68. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.ko.md +0 -0
  69. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.md +0 -0
  70. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.ru.md +0 -0
  71. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.zh-CN.md +0 -0
  72. {execweave-0.8.12 → execweave-0.8.14}/docs/cursor-hooks.zh-TW.md +0 -0
  73. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.de.md +0 -0
  74. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.fr.md +0 -0
  75. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.ja.md +0 -0
  76. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.ko.md +0 -0
  77. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.md +0 -0
  78. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.ru.md +0 -0
  79. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.zh-CN.md +0 -0
  80. {execweave-0.8.12 → execweave-0.8.14}/docs/evidence-grades.zh-TW.md +0 -0
  81. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.de.md +0 -0
  82. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.fr.md +0 -0
  83. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.ja.md +0 -0
  84. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.ko.md +0 -0
  85. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.md +0 -0
  86. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.ru.md +0 -0
  87. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.zh-CN.md +0 -0
  88. {execweave-0.8.12 → execweave-0.8.14}/docs/inference-gateway.zh-TW.md +0 -0
  89. {execweave-0.8.12 → execweave-0.8.14}/docs/internal/provider-capability-matrix.md +0 -0
  90. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.de.md +0 -0
  91. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.fr.md +0 -0
  92. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.ja.md +0 -0
  93. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.ko.md +0 -0
  94. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.md +0 -0
  95. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.ru.md +0 -0
  96. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.zh-CN.md +0 -0
  97. {execweave-0.8.12 → execweave-0.8.14}/docs/live-graph.zh-TW.md +0 -0
  98. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.de.md +0 -0
  99. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.fr.md +0 -0
  100. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.ja.md +0 -0
  101. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.ko.md +0 -0
  102. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.md +0 -0
  103. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.ru.md +0 -0
  104. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.zh-CN.md +0 -0
  105. {execweave-0.8.12 → execweave-0.8.14}/docs/model-runtime.zh-TW.md +0 -0
  106. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.de.md +0 -0
  107. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.fr.md +0 -0
  108. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.ja.md +0 -0
  109. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.ko.md +0 -0
  110. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.md +0 -0
  111. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.ru.md +0 -0
  112. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.zh-CN.md +0 -0
  113. {execweave-0.8.12 → execweave-0.8.14}/docs/opencode-plugin.zh-TW.md +0 -0
  114. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.de.md +0 -0
  115. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.fr.md +0 -0
  116. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.ja.md +0 -0
  117. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.ko.md +0 -0
  118. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.md +0 -0
  119. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.ru.md +0 -0
  120. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.zh-CN.md +0 -0
  121. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-1-runtime-collection.zh-TW.md +0 -0
  122. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.de.md +0 -0
  123. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.fr.md +0 -0
  124. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.ja.md +0 -0
  125. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.ko.md +0 -0
  126. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.md +0 -0
  127. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.ru.md +0 -0
  128. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.zh-CN.md +0 -0
  129. {execweave-0.8.12 → execweave-0.8.14}/docs/phase-2-execution-graph.zh-TW.md +0 -0
  130. {execweave-0.8.12 → execweave-0.8.14}/docs/remaining-provider-audit-v0.8.7.md +0 -0
  131. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.de.md +0 -0
  132. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.fr.md +0 -0
  133. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.ja.md +0 -0
  134. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.ko.md +0 -0
  135. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.md +0 -0
  136. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.ru.md +0 -0
  137. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.zh-CN.md +0 -0
  138. {execweave-0.8.12 → execweave-0.8.14}/docs/rule-packs.zh-TW.md +0 -0
  139. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.de.md +0 -0
  140. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.fr.md +0 -0
  141. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.ja.md +0 -0
  142. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.ko.md +0 -0
  143. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.md +0 -0
  144. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.ru.md +0 -0
  145. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.zh-CN.md +0 -0
  146. {execweave-0.8.12 → execweave-0.8.14}/docs/run-integrity.zh-TW.md +0 -0
  147. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.de.md +0 -0
  148. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.fr.md +0 -0
  149. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.ja.md +0 -0
  150. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.ko.md +0 -0
  151. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.md +0 -0
  152. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.ru.md +0 -0
  153. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.zh-CN.md +0 -0
  154. {execweave-0.8.12 → execweave-0.8.14}/docs/runtime-threat-model.zh-TW.md +0 -0
  155. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.de.md +0 -0
  156. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.fr.md +0 -0
  157. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.ja.md +0 -0
  158. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.ko.md +0 -0
  159. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.md +0 -0
  160. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.ru.md +0 -0
  161. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.zh-CN.md +0 -0
  162. {execweave-0.8.12 → execweave-0.8.14}/docs/security-analysis.zh-TW.md +0 -0
  163. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.de.md +0 -0
  164. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.fr.md +0 -0
  165. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.ja.md +0 -0
  166. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.ko.md +0 -0
  167. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.md +0 -0
  168. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.ru.md +0 -0
  169. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.zh-CN.md +0 -0
  170. {execweave-0.8.12 → execweave-0.8.14}/docs/semantic-telemetry.zh-TW.md +0 -0
  171. {execweave-0.8.12 → execweave-0.8.14}/docs/v0.6.5-hardening-decisions.md +0 -0
  172. {execweave-0.8.12 → execweave-0.8.14}/docs/v0.8.3-graph-ergonomics.md +0 -0
  173. {execweave-0.8.12 → execweave-0.8.14}/scripts/_check_release_stage_integrity_impl.py +0 -0
  174. {execweave-0.8.12 → execweave-0.8.14}/scripts/_dashboard_acceptance_impl.py +0 -0
  175. {execweave-0.8.12 → execweave-0.8.14}/scripts/_ollama_interactive_acceptance_impl.py +0 -0
  176. {execweave-0.8.12 → execweave-0.8.14}/scripts/_ollama_visible_acceptance_impl.py +0 -0
  177. {execweave-0.8.12 → execweave-0.8.14}/scripts/_python_native_acceptance_impl.py +0 -0
  178. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/__init__.py +0 -0
  179. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/browser_diagnostics.py +0 -0
  180. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/contracts.py +0 -0
  181. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/g5_runner.py +0 -0
  182. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/g6_runner.py +0 -0
  183. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/interrupt_guard.py +0 -0
  184. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/processes.py +0 -0
  185. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/reporting.py +0 -0
  186. {execweave-0.8.12 → execweave-0.8.14}/scripts/acceptance/terminal_output.py +0 -0
  187. {execweave-0.8.12 → execweave-0.8.14}/scripts/annotate_pytest_failures.py +0 -0
  188. {execweave-0.8.12 → execweave-0.8.14}/scripts/audit_i18n_parity.py +0 -0
  189. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_claude_hook.py +0 -0
  190. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_claude_record_graph.py +0 -0
  191. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_codex_hook.py +0 -0
  192. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_conversation_records.py +0 -0
  193. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_correlation_graph.py +0 -0
  194. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_inference_gateway_cli.py +0 -0
  195. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_model_runtime_cli.py +0 -0
  196. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_openai_compatible_cli.py +0 -0
  197. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_release_stage_integrity.py +0 -0
  198. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_semantic_graph.py +0 -0
  199. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_viewer_js.py +0 -0
  200. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_wheel_install.py +0 -0
  201. {execweave-0.8.12 → execweave-0.8.14}/scripts/check_windows_launchers.py +0 -0
  202. {execweave-0.8.12 → execweave-0.8.14}/scripts/dashboard_acceptance.py +0 -0
  203. {execweave-0.8.12 → execweave-0.8.14}/scripts/emit_claude_hook_smoke.py +0 -0
  204. {execweave-0.8.12 → execweave-0.8.14}/scripts/emit_codex_hook_smoke.py +0 -0
  205. {execweave-0.8.12 → execweave-0.8.14}/scripts/emit_cursor_hook_smoke.py +0 -0
  206. {execweave-0.8.12 → execweave-0.8.14}/scripts/emit_opencode_plugin_smoke.py +0 -0
  207. {execweave-0.8.12 → execweave-0.8.14}/scripts/make_semantic_smoke.py +0 -0
  208. {execweave-0.8.12 → execweave-0.8.14}/scripts/measure_graph_metrics.py +0 -0
  209. {execweave-0.8.12 → execweave-0.8.14}/scripts/ollama_interactive_acceptance.py +0 -0
  210. {execweave-0.8.12 → execweave-0.8.14}/scripts/ollama_visible_acceptance.py +0 -0
  211. {execweave-0.8.12 → execweave-0.8.14}/scripts/owned_cleanup_acceptance.py +0 -0
  212. {execweave-0.8.12 → execweave-0.8.14}/scripts/probe_provider_capability.py +0 -0
  213. {execweave-0.8.12 → execweave-0.8.14}/scripts/python_native_acceptance.py +0 -0
  214. {execweave-0.8.12 → execweave-0.8.14}/scripts/sync_i18n_nav.py +0 -0
  215. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/__main__.py +0 -0
  216. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/_conversation_records_core.py +0 -0
  217. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/_dashboard_shell_base.py +0 -0
  218. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/_http_proxy_base.py +0 -0
  219. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/_http_proxy_bounded.py +0 -0
  220. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/_http_proxy_stage.py +0 -0
  221. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/agent_bootstrap.py +0 -0
  222. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/agent_topology.py +0 -0
  223. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/agent_trace.py +0 -0
  224. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/agy_preview_sanitize.py +0 -0
  225. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/analysis.py +0 -0
  226. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/anthropic.py +0 -0
  227. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/anthropic_cli.py +0 -0
  228. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/anthropic_full_fidelity.py +0 -0
  229. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_adapter.py +0 -0
  230. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_adapter_base.py +0 -0
  231. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_full_fidelity.py +0 -0
  232. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_full_fidelity_base.py +0 -0
  233. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
  234. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_hook_cli.py +0 -0
  235. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_record.py +0 -0
  236. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_subagent_linkage.py +0 -0
  237. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/antigravity_trace_capability.py +0 -0
  238. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/auto_specialized.py +0 -0
  239. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/backends.py +0 -0
  240. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/benchmark.py +0 -0
  241. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_adapter.py +0 -0
  242. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_child_transcript.py +0 -0
  243. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_delegation.py +0 -0
  244. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_full_fidelity.py +0 -0
  245. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_hook_cli.py +0 -0
  246. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_hook_contract.py +0 -0
  247. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_model_observer.py +0 -0
  248. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/claude_record.py +0 -0
  249. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cli.py +0 -0
  250. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_adapter.py +0 -0
  251. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_conversation.py +0 -0
  252. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_full_fidelity.py +0 -0
  253. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_hook_cli.py +0 -0
  254. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_hook_entry.py +0 -0
  255. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_hook_lifecycle.py +0 -0
  256. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_message_diagnostics.py +0 -0
  257. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_message_transport_diagnostics.py +0 -0
  258. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_record.py +0 -0
  259. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_rollout_structures.py +0 -0
  260. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_rollout_trace.py +0 -0
  261. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/codex_rollout_trace_base.py +0 -0
  262. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/content_evidence.py +0 -0
  263. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/content_store.py +0 -0
  264. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_archive.py +0 -0
  265. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_message_identity.py +0 -0
  266. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview.py +0 -0
  267. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_antigravity.py +0 -0
  268. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_claude.py +0 -0
  269. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_codex.py +0 -0
  270. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_common.py +0 -0
  271. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_generic.py +0 -0
  272. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_lines.py +0 -0
  273. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_preview_transcript.py +0 -0
  274. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_records.py +0 -0
  275. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_records_antigravity.py +0 -0
  276. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_records_codex.py +0 -0
  277. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_records_common.py +0 -0
  278. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/conversation_records_ollama.py +0 -0
  279. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/correlation.py +0 -0
  280. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_adapter.py +0 -0
  281. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_delegation.py +0 -0
  282. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_delegation_base.py +0 -0
  283. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_full_fidelity.py +0 -0
  284. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_hook_cli.py +0 -0
  285. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_hook_contract.py +0 -0
  286. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/cursor_record.py +0 -0
  287. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/dashboard_shell.py +0 -0
  288. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/entry.py +0 -0
  289. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/evidence_availability.py +0 -0
  290. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/evidence_grade.py +0 -0
  291. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/fidelity.py +0 -0
  292. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/filesystem.py +0 -0
  293. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/focus.py +0 -0
  294. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/graph.py +0 -0
  295. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/graph_ops.py +0 -0
  296. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/http_proxy.py +0 -0
  297. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/http_proxy_cli.py +0 -0
  298. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/inference_gateway.py +0 -0
  299. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/inference_gateway_cli.py +0 -0
  300. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/inference_gateway_full_fidelity.py +0 -0
  301. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/inference_identity.py +0 -0
  302. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/inference_identity_cli.py +0 -0
  303. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/integrity.py +0 -0
  304. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/integrity_cli.py +0 -0
  305. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/litellm_callback.py +0 -0
  306. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/litellm_callback_cli.py +0 -0
  307. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live.py +0 -0
  308. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_core.py +0 -0
  309. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view.py +0 -0
  310. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_extra_style.py +0 -0
  311. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_markup.py +0 -0
  312. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_process_layout.py +0 -0
  313. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_readability.py +0 -0
  314. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_script_a.py +0 -0
  315. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_script_b.py +0 -0
  316. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_script_c.py +0 -0
  317. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_script_d.py +0 -0
  318. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/live_view_style.py +0 -0
  319. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/model_runtime.py +0 -0
  320. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/model_runtime_cli.py +0 -0
  321. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/model_runtime_full_fidelity.py +0 -0
  322. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/openai_compatible.py +0 -0
  323. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/openai_compatible_cli.py +0 -0
  324. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/openai_compatible_full_fidelity.py +0 -0
  325. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_adapter.py +0 -0
  326. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_event_contract.py +0 -0
  327. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_full_fidelity.py +0 -0
  328. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_hook_cli.py +0 -0
  329. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_plugin_cli.py +0 -0
  330. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_record.py +0 -0
  331. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/opencode_task_linkage.py +0 -0
  332. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/overhead_benchmark.py +0 -0
  333. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/provider_capability.py +0 -0
  334. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/provider_lifecycle.py +0 -0
  335. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/provider_record.py +0 -0
  336. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/rule_pack.py +0 -0
  337. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/rule_pack_cli.py +0 -0
  338. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/scalability_benchmark.py +0 -0
  339. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/schema.py +0 -0
  340. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/scope.py +0 -0
  341. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/semantic.py +0 -0
  342. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/sink.py +0 -0
  343. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/strace_backend.py +0 -0
  344. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/stream_assembly.py +0 -0
  345. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/theme.py +0 -0
  346. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/top.py +0 -0
  347. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/top_cli.py +0 -0
  348. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/validate.py +0 -0
  349. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/vendor/dagre.min.js +0 -0
  350. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/view_cli.py +0 -0
  351. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer.py +0 -0
  352. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel.py +0 -0
  353. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
  354. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_claude.py +0 -0
  355. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_codex.py +0 -0
  356. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_cursor.py +0 -0
  357. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_default.py +0 -0
  358. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_ollama.py +0 -0
  359. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_opencode.py +0 -0
  360. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_agent_panel_registry.py +0 -0
  361. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_content_inspector.py +0 -0
  362. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_dashboard_clean.py +0 -0
  363. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_dashboard_focus.py +0 -0
  364. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_dashboard_hardening.py +0 -0
  365. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
  366. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_external_endpoints.py +0 -0
  367. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_limits.py +0 -0
  368. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_live_layout.py +0 -0
  369. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_projection.py +0 -0
  370. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_projection_base.py +0 -0
  371. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/viewer_semantic_projection.py +0 -0
  372. {execweave-0.8.12 → execweave-0.8.14}/src/execweave/workflow.py +0 -0
  373. {execweave-0.8.12 → execweave-0.8.14}/tests/dashboard_readability_fixture.py +0 -0
  374. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/codex_multi_agent/PROVENANCE.md +0 -0
  375. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/codex_multi_agent/hook-payloads.json +0 -0
  376. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/codex_multi_agent/rollout-main.jsonl +0 -0
  377. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/hooks/README.md +0 -0
  378. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/hooks/claude.json +0 -0
  379. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/hooks/codex.json +0 -0
  380. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/hooks/cursor.json +0 -0
  381. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/hooks/manifest.json +0 -0
  382. {execweave-0.8.12 → execweave-0.8.14}/tests/fixtures/hooks/opencode.json +0 -0
  383. {execweave-0.8.12 → execweave-0.8.14}/tests/multi_agent_run_fixture.py +0 -0
  384. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_browser_diagnostics_e2e.py +0 -0
  385. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_conpty_selection.py +0 -0
  386. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_interrupt_guard.py +0 -0
  387. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_owned_processes.py +0 -0
  388. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_required_capabilities.py +0 -0
  389. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_terminal_output.py +0 -0
  390. {execweave-0.8.12 → execweave-0.8.14}/tests/test_acceptance_visible_pipe.py +0 -0
  391. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_bootstrap.py +0 -0
  392. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_message_viewer.py +0 -0
  393. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_node_labels.py +0 -0
  394. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_said_panel.py +0 -0
  395. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_topology_evidence.py +0 -0
  396. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_trace_lifecycle.py +0 -0
  397. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agent_trace_viewer_visibility.py +0 -0
  398. {execweave-0.8.12 → execweave-0.8.14}/tests/test_agy_windows_wire_acceptance.py +0 -0
  399. {execweave-0.8.12 → execweave-0.8.14}/tests/test_analysis.py +0 -0
  400. {execweave-0.8.12 → execweave-0.8.14}/tests/test_anthropic.py +0 -0
  401. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_agent_collaboration.py +0 -0
  402. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_child_panel_policy.py +0 -0
  403. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_child_transcript_tools.py +0 -0
  404. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_cursor_launch.py +0 -0
  405. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_field_run_regressions.py +0 -0
  406. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_history_replay.py +0 -0
  407. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_identity_topology.py +0 -0
  408. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_invocation_archive.py +0 -0
  409. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_lifecycle.py +0 -0
  410. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_linkage_projection.py +0 -0
  411. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_multi_conversation_isolation.py +0 -0
  412. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_official_contract.py +0 -0
  413. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_role_path_fallback.py +0 -0
  414. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_root_child_history_v2.py +0 -0
  415. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_subagent_transcript_linkage.py +0 -0
  416. {execweave-0.8.12 → execweave-0.8.14}/tests/test_antigravity_trace_capability_cli.py +0 -0
  417. {execweave-0.8.12 → execweave-0.8.14}/tests/test_auto_specialized.py +0 -0
  418. {execweave-0.8.12 → execweave-0.8.14}/tests/test_auto_specialized_ollama_two_phase.py +0 -0
  419. {execweave-0.8.12 → execweave-0.8.14}/tests/test_backends.py +0 -0
  420. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_adapter.py +0 -0
  421. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_child_transcript_tools.py +0 -0
  422. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_delegation.py +0 -0
  423. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_full_fidelity.py +0 -0
  424. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_hook_contract.py +0 -0
  425. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_hook_metadata.py +0 -0
  426. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_hook_viewer.py +0 -0
  427. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_model_observer.py +0 -0
  428. {execweave-0.8.12 → execweave-0.8.14}/tests/test_claude_record.py +0 -0
  429. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cleanup_finalizer_identity.py +0 -0
  430. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_adapter.py +0 -0
  431. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_archive_full_fidelity.py +0 -0
  432. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_child_panel_policy.py +0 -0
  433. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_conversation_isolation.py +0 -0
  434. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_full_fidelity.py +0 -0
  435. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_hook_global_fail_open.py +0 -0
  436. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_hook_lifecycle.py +0 -0
  437. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_hook_partial_capture.py +0 -0
  438. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_interrupt_contract.py +0 -0
  439. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_message_diagnostics.py +0 -0
  440. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_message_transport_diagnostics.py +0 -0
  441. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_nickname_path_fallback.py +0 -0
  442. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_plain_routed_agent_message.py +0 -0
  443. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_real_multi_agent_conversation.py +0 -0
  444. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_record.py +0 -0
  445. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_reducer_command.py +0 -0
  446. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_rollout_structures.py +0 -0
  447. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_rollout_trace.py +0 -0
  448. {execweave-0.8.12 → execweave-0.8.14}/tests/test_codex_routing_native_identity.py +0 -0
  449. {execweave-0.8.12 → execweave-0.8.14}/tests/test_collector.py +0 -0
  450. {execweave-0.8.12 → execweave-0.8.14}/tests/test_command.py +0 -0
  451. {execweave-0.8.12 → execweave-0.8.14}/tests/test_condense.py +0 -0
  452. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_access.py +0 -0
  453. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_agent_focus.py +0 -0
  454. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_agent_isolation.py +0 -0
  455. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_identity_merge.py +0 -0
  456. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_message_observation_dedupe.py +0 -0
  457. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_provider_parity.py +0 -0
  458. {execweave-0.8.12 → execweave-0.8.14}/tests/test_conversation_root_authority.py +0 -0
  459. {execweave-0.8.12 → execweave-0.8.14}/tests/test_correlation.py +0 -0
  460. {execweave-0.8.12 → execweave-0.8.14}/tests/test_correlation_canonical_path.py +0 -0
  461. {execweave-0.8.12 → execweave-0.8.14}/tests/test_correlation_checker.py +0 -0
  462. {execweave-0.8.12 → execweave-0.8.14}/tests/test_correlation_process_exe.py +0 -0
  463. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cross_provider_agent_trace.py +0 -0
  464. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_adapter.py +0 -0
  465. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_delegation.py +0 -0
  466. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_full_fidelity.py +0 -0
  467. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_hook_contract.py +0 -0
  468. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_hook_fail_open.py +0 -0
  469. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_ollama_session_lifecycle.py +0 -0
  470. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_record.py +0 -0
  471. {execweave-0.8.12 → execweave-0.8.14}/tests/test_cursor_task_linkage.py +0 -0
  472. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dagre_semantic_pipeline.py +0 -0
  473. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_acceptance_relative_output_e2e.py +0 -0
  474. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_acceptance_reporting.py +0 -0
  475. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_camera_scheduler_e2e.py +0 -0
  476. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_favicon.py +0 -0
  477. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_gif_export_e2e.py +0 -0
  478. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_information_architecture.py +0 -0
  479. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_initial_fit_readability_e2e.py +0 -0
  480. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_node_drag_camera_e2e.py +0 -0
  481. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_readability_e2e.py +0 -0
  482. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_round_fold_state_e2e.py +0 -0
  483. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_simplification.py +0 -0
  484. {execweave-0.8.12 → execweave-0.8.14}/tests/test_dashboard_ux_and_hook_projection.py +0 -0
  485. {execweave-0.8.12 → execweave-0.8.14}/tests/test_delegation_viewer.py +0 -0
  486. {execweave-0.8.12 → execweave-0.8.14}/tests/test_evidence_grade.py +0 -0
  487. {execweave-0.8.12 → execweave-0.8.14}/tests/test_execution_viewer.py +0 -0
  488. {execweave-0.8.12 → execweave-0.8.14}/tests/test_external_endpoints_all_providers.py +0 -0
  489. {execweave-0.8.12 → execweave-0.8.14}/tests/test_fidelity.py +0 -0
  490. {execweave-0.8.12 → execweave-0.8.14}/tests/test_filesystem_resilience.py +0 -0
  491. {execweave-0.8.12 → execweave-0.8.14}/tests/test_focus.py +0 -0
  492. {execweave-0.8.12 → execweave-0.8.14}/tests/test_fold_budget_setting.py +0 -0
  493. {execweave-0.8.12 → execweave-0.8.14}/tests/test_full_fidelity.py +0 -0
  494. {execweave-0.8.12 → execweave-0.8.14}/tests/test_g5_hardening_contract.py +0 -0
  495. {execweave-0.8.12 → execweave-0.8.14}/tests/test_g6_owned_parity_contract.py +0 -0
  496. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph.py +0 -0
  497. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph_arrange_constraints_e2e.py +0 -0
  498. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph_clear_focus_e2e.py +0 -0
  499. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph_edge_routing_e2e.py +0 -0
  500. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph_lane_separation_e2e.py +0 -0
  501. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph_node_sizing_e2e.py +0 -0
  502. {execweave-0.8.12 → execweave-0.8.14}/tests/test_graph_ops.py +0 -0
  503. {execweave-0.8.12 → execweave-0.8.14}/tests/test_hook_fixture_corpus.py +0 -0
  504. {execweave-0.8.12 → execweave-0.8.14}/tests/test_http_proxy.py +0 -0
  505. {execweave-0.8.12 → execweave-0.8.14}/tests/test_http_proxy_request_phase.py +0 -0
  506. {execweave-0.8.12 → execweave-0.8.14}/tests/test_http_proxy_response_memory.py +0 -0
  507. {execweave-0.8.12 → execweave-0.8.14}/tests/test_http_proxy_streaming.py +0 -0
  508. {execweave-0.8.12 → execweave-0.8.14}/tests/test_i18n_readme_policy.py +0 -0
  509. {execweave-0.8.12 → execweave-0.8.14}/tests/test_inference_endpoint_identity.py +0 -0
  510. {execweave-0.8.12 → execweave-0.8.14}/tests/test_inference_gateway.py +0 -0
  511. {execweave-0.8.12 → execweave-0.8.14}/tests/test_inference_gateway_full_fidelity.py +0 -0
  512. {execweave-0.8.12 → execweave-0.8.14}/tests/test_inference_identity.py +0 -0
  513. {execweave-0.8.12 → execweave-0.8.14}/tests/test_integrity.py +0 -0
  514. {execweave-0.8.12 → execweave-0.8.14}/tests/test_litellm_callback.py +0 -0
  515. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live.py +0 -0
  516. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live_auth.py +0 -0
  517. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live_dashboard.py +0 -0
  518. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live_dashboard_js.py +0 -0
  519. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live_delta.py +0 -0
  520. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live_logs_export.py +0 -0
  521. {execweave-0.8.12 → execweave-0.8.14}/tests/test_live_theme.py +0 -0
  522. {execweave-0.8.12 → execweave-0.8.14}/tests/test_lmstudio_auto_specialized.py +0 -0
  523. {execweave-0.8.12 → execweave-0.8.14}/tests/test_local_runtime_live_capture.py +0 -0
  524. {execweave-0.8.12 → execweave-0.8.14}/tests/test_model_runtime.py +0 -0
  525. {execweave-0.8.12 → execweave-0.8.14}/tests/test_model_runtime_full_fidelity.py +0 -0
  526. {execweave-0.8.12 → execweave-0.8.14}/tests/test_ollama_interactive_acceptance.py +0 -0
  527. {execweave-0.8.12 → execweave-0.8.14}/tests/test_ollama_interactive_terminal_semantics.py +0 -0
  528. {execweave-0.8.12 → execweave-0.8.14}/tests/test_ollama_panel_policy.py +0 -0
  529. {execweave-0.8.12 → execweave-0.8.14}/tests/test_ollama_serve_runtime_integration.py +0 -0
  530. {execweave-0.8.12 → execweave-0.8.14}/tests/test_ollama_visible_acceptance.py +0 -0
  531. {execweave-0.8.12 → execweave-0.8.14}/tests/test_openai_compatible.py +0 -0
  532. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_adapter.py +0 -0
  533. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_event_contract.py +0 -0
  534. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_event_lifecycle.py +0 -0
  535. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_full_fidelity.py +0 -0
  536. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_identity_unification.py +0 -0
  537. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_plugin.py +0 -0
  538. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_record.py +0 -0
  539. {execweave-0.8.12 → execweave-0.8.14}/tests/test_opencode_task_session_linkage.py +0 -0
  540. {execweave-0.8.12 → execweave-0.8.14}/tests/test_overhead_benchmark.py +0 -0
  541. {execweave-0.8.12 → execweave-0.8.14}/tests/test_per_agent_conversation_default.py +0 -0
  542. {execweave-0.8.12 → execweave-0.8.14}/tests/test_pr25_premerge_hardening_contract.py +0 -0
  543. {execweave-0.8.12 → execweave-0.8.14}/tests/test_pr25_premerge_hardening_e2e.py +0 -0
  544. {execweave-0.8.12 → execweave-0.8.14}/tests/test_pro6_audit_regressions.py +0 -0
  545. {execweave-0.8.12 → execweave-0.8.14}/tests/test_process_tree_layout.py +0 -0
  546. {execweave-0.8.12 → execweave-0.8.14}/tests/test_provider_capability.py +0 -0
  547. {execweave-0.8.12 → execweave-0.8.14}/tests/test_provider_conversation_evidence.py +0 -0
  548. {execweave-0.8.12 → execweave-0.8.14}/tests/test_provider_conversation_history_integrity.py +0 -0
  549. {execweave-0.8.12 → execweave-0.8.14}/tests/test_provider_dashboard_contract.py +0 -0
  550. {execweave-0.8.12 → execweave-0.8.14}/tests/test_provider_lifecycle.py +0 -0
  551. {execweave-0.8.12 → execweave-0.8.14}/tests/test_provider_neutral_viewer_semantics.py +0 -0
  552. {execweave-0.8.12 → execweave-0.8.14}/tests/test_python_native_acceptance.py +0 -0
  553. {execweave-0.8.12 → execweave-0.8.14}/tests/test_relay_prompt_live_e2e.py +0 -0
  554. {execweave-0.8.12 → execweave-0.8.14}/tests/test_release_stage_integrity_version_guard.py +0 -0
  555. {execweave-0.8.12 → execweave-0.8.14}/tests/test_rule_pack.py +0 -0
  556. {execweave-0.8.12 → execweave-0.8.14}/tests/test_schema.py +0 -0
  557. {execweave-0.8.12 → execweave-0.8.14}/tests/test_scope.py +0 -0
  558. {execweave-0.8.12 → execweave-0.8.14}/tests/test_semantic.py +0 -0
  559. {execweave-0.8.12 → execweave-0.8.14}/tests/test_shared_injected_context_scope.py +0 -0
  560. {execweave-0.8.12 → execweave-0.8.14}/tests/test_single_agent_barycenter.py +0 -0
  561. {execweave-0.8.12 → execweave-0.8.14}/tests/test_strace_backend.py +0 -0
  562. {execweave-0.8.12 → execweave-0.8.14}/tests/test_stream_assembly.py +0 -0
  563. {execweave-0.8.12 → execweave-0.8.14}/tests/test_threat_model.py +0 -0
  564. {execweave-0.8.12 → execweave-0.8.14}/tests/test_tool_traffic_e2e.py +0 -0
  565. {execweave-0.8.12 → execweave-0.8.14}/tests/test_top_detached.py +0 -0
  566. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v063_features.py +0 -0
  567. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v064_live_auto_integrations.py +0 -0
  568. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v064_live_evidence.py +0 -0
  569. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v079_review_e2e.py +0 -0
  570. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v079_review_regressions.py +0 -0
  571. {execweave-0.8.12 → execweave-0.8.14}/tests/test_v083_release_gate_p2.py +0 -0
  572. {execweave-0.8.12 → execweave-0.8.14}/tests/test_validate.py +0 -0
  573. {execweave-0.8.12 → execweave-0.8.14}/tests/test_version.py +0 -0
  574. {execweave-0.8.12 → execweave-0.8.14}/tests/test_viewer.py +0 -0
  575. {execweave-0.8.12 → execweave-0.8.14}/tests/test_viewer_agent_isolation_e2e.py +0 -0
  576. {execweave-0.8.12 → execweave-0.8.14}/tests/test_viewer_child_authority.py +0 -0
  577. {execweave-0.8.12 → execweave-0.8.14}/tests/test_viewer_content_inspector.py +0 -0
  578. {execweave-0.8.12 → execweave-0.8.14}/tests/test_viewer_limits.py +0 -0
  579. {execweave-0.8.12 → execweave-0.8.14}/tests/test_viewer_projection.py +0 -0
  580. {execweave-0.8.12 → execweave-0.8.14}/tests/test_visual_ux_readability.py +0 -0
  581. {execweave-0.8.12 → execweave-0.8.14}/tests/test_windows_codex_agy_display_repair.py +0 -0
  582. {execweave-0.8.12 → execweave-0.8.14}/tests/test_workflow.py +0 -0
  583. {execweave-0.8.12 → 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.12
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.12 release metadata
8
- version = "0.8.12"
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"
@@ -1,3 +1,3 @@
1
1
  """ExecWeave runtime graph package."""
2
2
 
3
- __version__ = "0.8.12"
3
+ __version__ = "0.8.14"
@@ -123,12 +123,35 @@ 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
129
130
  self._network_sample_errors = 0
130
131
  self._network_access_denied = 0
131
132
 
133
+ def _filesystem_excluded_roots(self) -> list[Path]:
134
+ """Return ExecWeave-owned paths that must never become workload evidence.
135
+
136
+ The default ``.execweave`` tree and the runtime event stream were already
137
+ internal. Live mode can also place ``events.jsonl`` and ``semantic.jsonl``
138
+ together in a caller-selected output directory inside the watch root. When
139
+ those files are siblings, exclude their whole run directory so ExecWeave's
140
+ own evidence writes cannot recursively manufacture filesystem evidence.
141
+ A separately configured semantic sidecar remains an exact-file exclusion.
142
+ """
143
+ sink_path = self.sink.path.expanduser().resolve()
144
+ excluded = [(self.watch_root / ".execweave").resolve(), sink_path]
145
+ configured = os.environ.get("EXECWEAVE_SEMANTIC_SIDECAR")
146
+ if not configured:
147
+ return excluded
148
+
149
+ semantic_path = Path(configured).expanduser().resolve()
150
+ excluded.append(
151
+ semantic_path.parent if semantic_path.parent == sink_path.parent else semantic_path
152
+ )
153
+ return excluded
154
+
132
155
  def run(self, command: list[str]) -> int:
133
156
  if not command:
134
157
  raise ValueError("command must not be empty")
@@ -163,17 +186,17 @@ class RuntimeCollector:
163
186
  )
164
187
 
165
188
  watcher: FileWatcher | None = None
166
- internal_root = self.watch_root / ".execweave"
167
189
  if self.collect_filesystem:
168
190
  watcher = FileWatcher(
169
191
  root=self.watch_root,
170
192
  session_id=self.session_id,
171
193
  session_entity=session,
172
194
  sink=self.sink,
173
- excluded_roots=[internal_root, self.sink.path],
195
+ excluded_roots=self._filesystem_excluded_roots(),
174
196
  )
175
197
 
176
198
  process: subprocess.Popen[bytes] | None = None
199
+ owned: list[psutil.Process] = []
177
200
  return_code = 1
178
201
  interrupted = False
179
202
  collector_error_type: str | None = None
@@ -209,8 +232,6 @@ class RuntimeCollector:
209
232
  except KeyboardInterrupt:
210
233
  interrupted = True
211
234
  return_code = 130
212
- if process is not None:
213
- self._terminate_process_tree(process)
214
235
 
215
236
  if not interrupted:
216
237
  run_post_command_specialized_probe(
@@ -220,16 +241,24 @@ class RuntimeCollector:
220
241
  return return_code
221
242
  except BaseException as exc:
222
243
  collector_error_type = type(exc).__name__
223
- if process is not None and process.poll() is None:
224
- self._terminate_process_tree(process)
225
- workload_terminated_due_to_collector_error = True
226
244
  raise
227
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)
228
255
  if watcher is not None:
229
256
  watcher.stop()
230
- workload_alive_after_cleanup = bool(
231
- process is not None and process.poll() is None
232
- )
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))
233
262
  self.sink.emit(
234
263
  RuntimeEvent.create(
235
264
  session_id=self.session_id,
@@ -258,33 +287,95 @@ class RuntimeCollector:
258
287
  )
259
288
 
260
289
  @staticmethod
261
- def _terminate_process_tree(process: subprocess.Popen[bytes]) -> None:
262
- descendants: list[psutil.Process] = []
290
+ def _process_is_live(proc: psutil.Process) -> bool:
291
+ try:
292
+ if not proc.is_running():
293
+ return False
294
+ try:
295
+ return proc.status() != psutil.STATUS_ZOMBIE
296
+ except psutil.AccessDenied:
297
+ return True
298
+ except (psutil.NoSuchProcess, psutil.ZombieProcess):
299
+ return False
300
+
301
+ def _process_for_snapshot(self, snapshot: ProcessSnapshot) -> psutil.Process | None:
263
302
  try:
264
- root = psutil.Process(process.pid)
265
- descendants = root.children(recursive=True)
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
266
309
  except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
267
- pass
310
+ return None
268
311
 
269
- for child in reversed(descendants):
312
+ def _owned_live_processes(
313
+ self,
314
+ process: subprocess.Popen[bytes],
315
+ ) -> list[psutil.Process]:
316
+ """Return live processes still owned by this collector's launched workload.
317
+
318
+ A shell or launcher can exit before its children. Relying only on the current
319
+ root process tree then loses those reparented descendants. The collector's
320
+ lifetime-qualified process snapshots preserve enough ownership evidence to
321
+ find and clean them without risking a reused PID.
322
+ """
323
+ owned: dict[int, psutil.Process] = {}
324
+
325
+ def add_with_descendants(candidate: psutil.Process) -> None:
326
+ if not self._process_is_live(candidate):
327
+ return
328
+ owned[candidate.pid] = candidate
270
329
  try:
271
- child.terminate()
330
+ descendants = candidate.children(recursive=True)
272
331
  except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
273
- pass
332
+ descendants = []
333
+ for child in descendants:
334
+ if self._process_is_live(child):
335
+ owned[child.pid] = child
274
336
 
275
337
  if process.poll() is None:
276
338
  try:
277
- process.terminate()
278
- except OSError:
339
+ add_with_descendants(psutil.Process(process.pid))
340
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
341
+ pass
342
+
343
+ snapshots = {**self._seen_processes, **self._discovered_processes}
344
+ for snapshot in snapshots.values():
345
+ tracked = self._process_for_snapshot(snapshot)
346
+ if tracked is not None:
347
+ add_with_descendants(tracked)
348
+
349
+ return list(owned.values())
350
+
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)
361
+ # Terminate descendants/tracked orphans before the launcher/root when it is
362
+ # still alive. Holding psutil handles also keeps cleanup robust if a parent
363
+ # exits while the loop is running.
364
+ for candidate in sorted(owned, key=lambda item: item.pid == process.pid):
365
+ try:
366
+ candidate.terminate()
367
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
279
368
  pass
280
369
 
281
- if descendants:
282
- _, alive = psutil.wait_procs(descendants, timeout=2.0)
283
- for child in alive:
370
+ if owned:
371
+ _, alive = psutil.wait_procs(owned, timeout=2.0)
372
+ for candidate in alive:
284
373
  try:
285
- child.kill()
374
+ candidate.kill()
286
375
  except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
287
376
  pass
377
+ if alive:
378
+ psutil.wait_procs(alive, timeout=2.0)
288
379
 
289
380
  try:
290
381
  process.wait(timeout=2.0)
@@ -319,6 +410,11 @@ class RuntimeCollector:
319
410
  current[snapshot.pid] = snapshot
320
411
  process_objects[snapshot.pid] = proc
321
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
322
418
  for snapshot in current.values():
323
419
  previous = self._seen_processes.get(snapshot.pid)
324
420
  if previous is None or not self._same_process_lifetime(previous, snapshot):
@@ -80,7 +80,12 @@ def _resolve_executable(executable: str, *, path: str | None = None) -> str:
80
80
  candidate = Path(executable).expanduser()
81
81
  if not candidate.is_file():
82
82
  raise FileNotFoundError(f"command executable not found: {executable!r}")
83
- resolved = str(candidate.resolve())
83
+ # Keep the user-selected launcher path itself. In particular, a virtualenv
84
+ # Python executable is commonly a symlink to the base interpreter on POSIX;
85
+ # dereferencing it changes Python's prefix discovery and silently drops the
86
+ # virtualenv site-packages. ``abspath`` normalizes the argv path without
87
+ # resolving symlinks.
88
+ resolved = os.path.abspath(os.fspath(candidate))
84
89
  else:
85
90
  path_launcher = shutil.which(executable, path=path)
86
91
  if executable.lower() == "cursor" and _prefer_cursor_desktop_launcher():
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ import time
7
+ import venv
8
+ from pathlib import Path
9
+
10
+ import psutil
11
+ import pytest
12
+
13
+ from execweave.collector import RuntimeCollector, _safe_process_snapshot
14
+ from execweave.command import resolve_launch_command
15
+ from execweave.sink import JsonlSink
16
+
17
+
18
+ def _process_is_live(pid: int) -> bool:
19
+ try:
20
+ process = psutil.Process(pid)
21
+ return process.is_running() and process.status() != psutil.STATUS_ZOMBIE
22
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
23
+ return False
24
+
25
+
26
+ def _wait_for(predicate, *, timeout: float = 5.0) -> None:
27
+ deadline = time.monotonic() + timeout
28
+ while time.monotonic() < deadline:
29
+ if predicate():
30
+ return
31
+ time.sleep(0.02)
32
+ raise AssertionError("condition did not become true before timeout")
33
+
34
+
35
+ def test_explicit_virtualenv_python_keeps_launcher_and_site_prefix(tmp_path: Path) -> None:
36
+ venv_root = tmp_path / ".venv"
37
+ venv.EnvBuilder(with_pip=False, symlinks=os.name != "nt").create(venv_root)
38
+ venv_python = (
39
+ venv_root / "Scripts" / "python.exe"
40
+ if os.name == "nt"
41
+ else venv_root / "bin" / "python"
42
+ )
43
+ if os.name != "nt":
44
+ assert venv_python.is_symlink()
45
+
46
+ launch = resolve_launch_command(
47
+ [str(venv_python), "-c", "import sys; print(sys.prefix)"]
48
+ )
49
+
50
+ assert launch[0] == os.path.abspath(os.fspath(venv_python))
51
+ if os.name != "nt":
52
+ assert Path(launch[0]).is_symlink()
53
+ completed = subprocess.run(
54
+ launch,
55
+ check=True,
56
+ capture_output=True,
57
+ text=True,
58
+ )
59
+ assert Path(completed.stdout.strip()).resolve() == venv_root.resolve()
60
+
61
+
62
+ def test_live_sibling_sidecar_excludes_entire_internal_output_dir(
63
+ monkeypatch: pytest.MonkeyPatch,
64
+ tmp_path: Path,
65
+ ) -> None:
66
+ run_dir = tmp_path / "custom-live-output"
67
+ run_dir.mkdir()
68
+ event_path = run_dir / "events.jsonl"
69
+ semantic_path = run_dir / "semantic.jsonl"
70
+ monkeypatch.setenv("EXECWEAVE_SEMANTIC_SIDECAR", str(semantic_path))
71
+
72
+ collector = RuntimeCollector(
73
+ session_id="d001",
74
+ sink=JsonlSink(event_path),
75
+ watch_root=tmp_path,
76
+ poll_interval=0.02,
77
+ collect_filesystem=True,
78
+ collect_network=False,
79
+ )
80
+
81
+ excluded = collector._filesystem_excluded_roots()
82
+ assert run_dir.resolve() in excluded
83
+ assert event_path.resolve() in excluded
84
+
85
+
86
+ def test_separate_semantic_sidecar_does_not_hide_unrelated_parent_directory(
87
+ monkeypatch: pytest.MonkeyPatch,
88
+ tmp_path: Path,
89
+ ) -> None:
90
+ run_dir = tmp_path / "runtime-output"
91
+ sidecar_dir = tmp_path / "user-selected-sidecar-dir"
92
+ run_dir.mkdir()
93
+ sidecar_dir.mkdir()
94
+ semantic_path = sidecar_dir / "semantic.jsonl"
95
+ monkeypatch.setenv("EXECWEAVE_SEMANTIC_SIDECAR", str(semantic_path))
96
+
97
+ collector = RuntimeCollector(
98
+ session_id="d001-separate",
99
+ sink=JsonlSink(run_dir / "events.jsonl"),
100
+ watch_root=tmp_path,
101
+ poll_interval=0.02,
102
+ collect_filesystem=True,
103
+ collect_network=False,
104
+ )
105
+
106
+ excluded = collector._filesystem_excluded_roots()
107
+ assert semantic_path.resolve() in excluded
108
+ assert sidecar_dir.resolve() not in excluded
109
+
110
+
111
+ def test_cleanup_terminates_tracked_child_after_launcher_has_exited(tmp_path: Path) -> None:
112
+ child_pid_path = tmp_path / "child.pid"
113
+ release_parent_path = tmp_path / "release-parent"
114
+ parent_code = r'''
115
+ import subprocess
116
+ import sys
117
+ import time
118
+ from pathlib import Path
119
+
120
+ pid_path = Path(sys.argv[1])
121
+ release_path = Path(sys.argv[2])
122
+ child = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(30)"])
123
+ pid_path.write_text(str(child.pid), encoding="utf-8")
124
+ while not release_path.exists():
125
+ time.sleep(0.02)
126
+ '''
127
+ parent = subprocess.Popen(
128
+ [
129
+ sys.executable,
130
+ "-c",
131
+ parent_code,
132
+ str(child_pid_path),
133
+ str(release_parent_path),
134
+ ]
135
+ )
136
+ child_pid: int | None = None
137
+ try:
138
+ _wait_for(child_pid_path.exists)
139
+ child_pid = int(child_pid_path.read_text(encoding="utf-8"))
140
+ child = psutil.Process(child_pid)
141
+ snapshot = _safe_process_snapshot(child)
142
+ assert snapshot is not None
143
+
144
+ collector = RuntimeCollector(
145
+ session_id="d003",
146
+ sink=JsonlSink(tmp_path / "events.jsonl"),
147
+ watch_root=tmp_path,
148
+ poll_interval=0.02,
149
+ collect_filesystem=False,
150
+ collect_network=False,
151
+ )
152
+ collector._seen_processes[child_pid] = snapshot
153
+
154
+ release_parent_path.touch()
155
+ parent.wait(timeout=5)
156
+ assert parent.poll() is not None
157
+ assert _process_is_live(child_pid)
158
+
159
+ collector._terminate_process_tree(parent)
160
+
161
+ _wait_for(lambda: not _process_is_live(child_pid))
162
+ assert not _process_is_live(child_pid)
163
+ finally:
164
+ if parent.poll() is None:
165
+ parent.kill()
166
+ parent.wait(timeout=5)
167
+ if child_pid is not None and _process_is_live(child_pid):
168
+ try:
169
+ psutil.Process(child_pid).kill()
170
+ except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
171
+ pass