execweave 0.8.13__tar.gz → 0.8.14__tar.gz

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