execweave 0.8.10__tar.gz → 0.8.11__tar.gz

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