execweave 0.8.15__tar.gz → 0.8.17__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 (592) hide show
  1. {execweave-0.8.15 → execweave-0.8.17}/PKG-INFO +12 -1
  2. {execweave-0.8.15 → execweave-0.8.17}/README.md +9 -0
  3. {execweave-0.8.15 → execweave-0.8.17}/pyproject.toml +12 -2
  4. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/__init__.py +1 -1
  5. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/_dashboard_shell_base.py +4 -2
  6. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/auto_specialized.py +56 -3
  7. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/collector.py +3 -1
  8. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_core.py +10 -0
  9. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view.py +0 -27
  10. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_process_layout.py +47 -91
  11. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_script_c.py +1 -1
  12. execweave-0.8.17/src/execweave/live_view_script_d.py +40 -0
  13. execweave-0.8.17/src/execweave/runtime_endpoint_availability.py +44 -0
  14. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/top.py +6 -0
  15. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_dashboard_clean.py +0 -5
  16. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_dashboard_focus.py +23 -5
  17. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_dashboard_hardening_v2.py +1 -22
  18. execweave-0.8.17/src/execweave/viewer_dashboard_pr70.py +261 -0
  19. execweave-0.8.17/src/execweave/viewer_gif.py +278 -0
  20. execweave-0.8.17/src/execweave/viewer_layout_geometry.py +118 -0
  21. execweave-0.8.17/src/execweave/viewer_projection_bridges.py +214 -0
  22. execweave-0.8.17/src/execweave/viewer_tool_mirror_identity.py +75 -0
  23. execweave-0.8.15/.github/workflows/ci.yml +0 -287
  24. execweave-0.8.15/.github/workflows/cleanup-workflow-history.yml +0 -98
  25. execweave-0.8.15/.github/workflows/i18n.yml +0 -35
  26. execweave-0.8.15/.github/workflows/package-benchmark.yml +0 -61
  27. execweave-0.8.15/.github/workflows/package-smoke.yml +0 -42
  28. execweave-0.8.15/.github/workflows/provider-capability-stage-integrity.yml +0 -220
  29. execweave-0.8.15/.github/workflows/provider-dashboard-contract.yml +0 -151
  30. execweave-0.8.15/.github/workflows/publish.yml +0 -87
  31. execweave-0.8.15/.github/workflows/scalability.yml +0 -54
  32. execweave-0.8.15/.github/workflows/viewer-agent-isolation.yml +0 -89
  33. execweave-0.8.15/.github/workflows/wheel-smoke.yml +0 -34
  34. execweave-0.8.15/.github/workflows/windows-launcher.yml +0 -43
  35. execweave-0.8.15/README.de.md +0 -302
  36. execweave-0.8.15/README.fr.md +0 -302
  37. execweave-0.8.15/README.ja.md +0 -302
  38. execweave-0.8.15/README.ko.md +0 -302
  39. execweave-0.8.15/README.ru.md +0 -302
  40. execweave-0.8.15/README.zh-CN.md +0 -302
  41. execweave-0.8.15/README.zh-TW.md +0 -302
  42. execweave-0.8.15/benchmarks/phase1_overhead.py +0 -5
  43. execweave-0.8.15/diagnostics/acceptance_hardening_20260906.md +0 -202
  44. execweave-0.8.15/diagnostics/audit_eight_children.py +0 -134
  45. execweave-0.8.15/diagnostics/audit_python_journey.py +0 -215
  46. execweave-0.8.15/diagnostics/audit_real_clicks.py +0 -83
  47. execweave-0.8.15/diagnostics/current_state_reaudit.md +0 -101
  48. execweave-0.8.15/diagnostics/execweave_full_audit.md +0 -468
  49. execweave-0.8.15/diagnostics/gate_status.md +0 -69
  50. execweave-0.8.15/diagnostics/gate_status_history_through_g3.md +0 -171
  51. execweave-0.8.15/diagnostics/github_pr_inventory.json +0 -402
  52. execweave-0.8.15/diagnostics/handoff_checkpoint_20260906.md +0 -98
  53. execweave-0.8.15/diagnostics/next_agent_handoff.md +0 -154
  54. execweave-0.8.15/diagnostics/pr_regression_map.md +0 -803
  55. execweave-0.8.15/docs/antigravity-hooks.md +0 -74
  56. execweave-0.8.15/docs/assets/codex.gif +0 -0
  57. execweave-0.8.15/docs/benchmarks/README.md +0 -46
  58. execweave-0.8.15/docs/benchmarks/v0.6.0-github-actions.json +0 -67
  59. execweave-0.8.15/docs/benchmarks/v0.6.0-github-actions.svg +0 -46
  60. execweave-0.8.15/docs/claude-code-hooks.de.md +0 -157
  61. execweave-0.8.15/docs/claude-code-hooks.fr.md +0 -157
  62. execweave-0.8.15/docs/claude-code-hooks.ja.md +0 -157
  63. execweave-0.8.15/docs/claude-code-hooks.ko.md +0 -157
  64. execweave-0.8.15/docs/claude-code-hooks.md +0 -157
  65. execweave-0.8.15/docs/claude-code-hooks.ru.md +0 -157
  66. execweave-0.8.15/docs/claude-code-hooks.zh-CN.md +0 -157
  67. execweave-0.8.15/docs/claude-code-hooks.zh-TW.md +0 -157
  68. execweave-0.8.15/docs/codex-hooks.de.md +0 -70
  69. execweave-0.8.15/docs/codex-hooks.fr.md +0 -70
  70. execweave-0.8.15/docs/codex-hooks.ja.md +0 -70
  71. execweave-0.8.15/docs/codex-hooks.ko.md +0 -70
  72. execweave-0.8.15/docs/codex-hooks.md +0 -70
  73. execweave-0.8.15/docs/codex-hooks.ru.md +0 -70
  74. execweave-0.8.15/docs/codex-hooks.zh-CN.md +0 -70
  75. execweave-0.8.15/docs/codex-hooks.zh-TW.md +0 -70
  76. execweave-0.8.15/docs/cursor-hooks.de.md +0 -58
  77. execweave-0.8.15/docs/cursor-hooks.fr.md +0 -58
  78. execweave-0.8.15/docs/cursor-hooks.ja.md +0 -58
  79. execweave-0.8.15/docs/cursor-hooks.ko.md +0 -58
  80. execweave-0.8.15/docs/cursor-hooks.md +0 -62
  81. execweave-0.8.15/docs/cursor-hooks.ru.md +0 -58
  82. execweave-0.8.15/docs/cursor-hooks.zh-CN.md +0 -58
  83. execweave-0.8.15/docs/cursor-hooks.zh-TW.md +0 -58
  84. execweave-0.8.15/docs/evidence-grades.de.md +0 -61
  85. execweave-0.8.15/docs/evidence-grades.fr.md +0 -61
  86. execweave-0.8.15/docs/evidence-grades.ja.md +0 -61
  87. execweave-0.8.15/docs/evidence-grades.ko.md +0 -61
  88. execweave-0.8.15/docs/evidence-grades.md +0 -61
  89. execweave-0.8.15/docs/evidence-grades.ru.md +0 -61
  90. execweave-0.8.15/docs/evidence-grades.zh-CN.md +0 -61
  91. execweave-0.8.15/docs/evidence-grades.zh-TW.md +0 -61
  92. execweave-0.8.15/docs/inference-gateway.de.md +0 -74
  93. execweave-0.8.15/docs/inference-gateway.fr.md +0 -74
  94. execweave-0.8.15/docs/inference-gateway.ja.md +0 -74
  95. execweave-0.8.15/docs/inference-gateway.ko.md +0 -74
  96. execweave-0.8.15/docs/inference-gateway.md +0 -74
  97. execweave-0.8.15/docs/inference-gateway.ru.md +0 -74
  98. execweave-0.8.15/docs/inference-gateway.zh-CN.md +0 -74
  99. execweave-0.8.15/docs/inference-gateway.zh-TW.md +0 -74
  100. execweave-0.8.15/docs/internal/provider-capability-matrix.md +0 -101
  101. execweave-0.8.15/docs/live-graph.de.md +0 -223
  102. execweave-0.8.15/docs/live-graph.fr.md +0 -223
  103. execweave-0.8.15/docs/live-graph.ja.md +0 -223
  104. execweave-0.8.15/docs/live-graph.ko.md +0 -223
  105. execweave-0.8.15/docs/live-graph.md +0 -223
  106. execweave-0.8.15/docs/live-graph.ru.md +0 -223
  107. execweave-0.8.15/docs/live-graph.zh-CN.md +0 -223
  108. execweave-0.8.15/docs/live-graph.zh-TW.md +0 -223
  109. execweave-0.8.15/docs/model-runtime.de.md +0 -61
  110. execweave-0.8.15/docs/model-runtime.fr.md +0 -61
  111. execweave-0.8.15/docs/model-runtime.ja.md +0 -61
  112. execweave-0.8.15/docs/model-runtime.ko.md +0 -61
  113. execweave-0.8.15/docs/model-runtime.md +0 -61
  114. execweave-0.8.15/docs/model-runtime.ru.md +0 -61
  115. execweave-0.8.15/docs/model-runtime.zh-CN.md +0 -61
  116. execweave-0.8.15/docs/model-runtime.zh-TW.md +0 -61
  117. execweave-0.8.15/docs/opencode-plugin.de.md +0 -54
  118. execweave-0.8.15/docs/opencode-plugin.fr.md +0 -54
  119. execweave-0.8.15/docs/opencode-plugin.ja.md +0 -54
  120. execweave-0.8.15/docs/opencode-plugin.ko.md +0 -54
  121. execweave-0.8.15/docs/opencode-plugin.md +0 -54
  122. execweave-0.8.15/docs/opencode-plugin.ru.md +0 -54
  123. execweave-0.8.15/docs/opencode-plugin.zh-CN.md +0 -54
  124. execweave-0.8.15/docs/opencode-plugin.zh-TW.md +0 -54
  125. execweave-0.8.15/docs/phase-1-runtime-collection.de.md +0 -322
  126. execweave-0.8.15/docs/phase-1-runtime-collection.fr.md +0 -322
  127. execweave-0.8.15/docs/phase-1-runtime-collection.ja.md +0 -322
  128. execweave-0.8.15/docs/phase-1-runtime-collection.ko.md +0 -322
  129. execweave-0.8.15/docs/phase-1-runtime-collection.md +0 -322
  130. execweave-0.8.15/docs/phase-1-runtime-collection.ru.md +0 -322
  131. execweave-0.8.15/docs/phase-1-runtime-collection.zh-CN.md +0 -312
  132. execweave-0.8.15/docs/phase-1-runtime-collection.zh-TW.md +0 -312
  133. execweave-0.8.15/docs/phase-2-execution-graph.de.md +0 -286
  134. execweave-0.8.15/docs/phase-2-execution-graph.fr.md +0 -286
  135. execweave-0.8.15/docs/phase-2-execution-graph.ja.md +0 -286
  136. execweave-0.8.15/docs/phase-2-execution-graph.ko.md +0 -286
  137. execweave-0.8.15/docs/phase-2-execution-graph.md +0 -286
  138. execweave-0.8.15/docs/phase-2-execution-graph.ru.md +0 -286
  139. execweave-0.8.15/docs/phase-2-execution-graph.zh-CN.md +0 -280
  140. execweave-0.8.15/docs/phase-2-execution-graph.zh-TW.md +0 -280
  141. execweave-0.8.15/docs/remaining-provider-audit-v0.8.7.md +0 -143
  142. execweave-0.8.15/docs/rule-packs.de.md +0 -77
  143. execweave-0.8.15/docs/rule-packs.fr.md +0 -77
  144. execweave-0.8.15/docs/rule-packs.ja.md +0 -77
  145. execweave-0.8.15/docs/rule-packs.ko.md +0 -77
  146. execweave-0.8.15/docs/rule-packs.md +0 -77
  147. execweave-0.8.15/docs/rule-packs.ru.md +0 -77
  148. execweave-0.8.15/docs/rule-packs.zh-CN.md +0 -77
  149. execweave-0.8.15/docs/rule-packs.zh-TW.md +0 -77
  150. execweave-0.8.15/docs/run-integrity.de.md +0 -52
  151. execweave-0.8.15/docs/run-integrity.fr.md +0 -52
  152. execweave-0.8.15/docs/run-integrity.ja.md +0 -52
  153. execweave-0.8.15/docs/run-integrity.ko.md +0 -52
  154. execweave-0.8.15/docs/run-integrity.md +0 -52
  155. execweave-0.8.15/docs/run-integrity.ru.md +0 -52
  156. execweave-0.8.15/docs/run-integrity.zh-CN.md +0 -52
  157. execweave-0.8.15/docs/run-integrity.zh-TW.md +0 -52
  158. execweave-0.8.15/docs/runtime-threat-model.de.md +0 -60
  159. execweave-0.8.15/docs/runtime-threat-model.fr.md +0 -60
  160. execweave-0.8.15/docs/runtime-threat-model.ja.md +0 -60
  161. execweave-0.8.15/docs/runtime-threat-model.ko.md +0 -60
  162. execweave-0.8.15/docs/runtime-threat-model.md +0 -60
  163. execweave-0.8.15/docs/runtime-threat-model.ru.md +0 -60
  164. execweave-0.8.15/docs/runtime-threat-model.zh-CN.md +0 -60
  165. execweave-0.8.15/docs/runtime-threat-model.zh-TW.md +0 -60
  166. execweave-0.8.15/docs/security-analysis.de.md +0 -178
  167. execweave-0.8.15/docs/security-analysis.fr.md +0 -178
  168. execweave-0.8.15/docs/security-analysis.ja.md +0 -178
  169. execweave-0.8.15/docs/security-analysis.ko.md +0 -178
  170. execweave-0.8.15/docs/security-analysis.md +0 -178
  171. execweave-0.8.15/docs/security-analysis.ru.md +0 -178
  172. execweave-0.8.15/docs/security-analysis.zh-CN.md +0 -170
  173. execweave-0.8.15/docs/security-analysis.zh-TW.md +0 -170
  174. execweave-0.8.15/docs/semantic-telemetry.de.md +0 -63
  175. execweave-0.8.15/docs/semantic-telemetry.fr.md +0 -63
  176. execweave-0.8.15/docs/semantic-telemetry.ja.md +0 -63
  177. execweave-0.8.15/docs/semantic-telemetry.ko.md +0 -63
  178. execweave-0.8.15/docs/semantic-telemetry.md +0 -63
  179. execweave-0.8.15/docs/semantic-telemetry.ru.md +0 -63
  180. execweave-0.8.15/docs/semantic-telemetry.zh-CN.md +0 -63
  181. execweave-0.8.15/docs/semantic-telemetry.zh-TW.md +0 -63
  182. execweave-0.8.15/docs/v0.6.5-hardening-decisions.md +0 -47
  183. execweave-0.8.15/docs/v0.8.3-graph-ergonomics.md +0 -180
  184. execweave-0.8.15/scripts/_check_release_stage_integrity_impl.py +0 -745
  185. execweave-0.8.15/scripts/_dashboard_acceptance_impl.py +0 -598
  186. execweave-0.8.15/scripts/_ollama_interactive_acceptance_impl.py +0 -806
  187. execweave-0.8.15/scripts/_ollama_visible_acceptance_impl.py +0 -852
  188. execweave-0.8.15/scripts/_python_native_acceptance_impl.py +0 -542
  189. execweave-0.8.15/scripts/acceptance/__init__.py +0 -1
  190. execweave-0.8.15/scripts/acceptance/browser_diagnostics.py +0 -81
  191. execweave-0.8.15/scripts/acceptance/contracts.py +0 -33
  192. execweave-0.8.15/scripts/acceptance/g5_runner.py +0 -468
  193. execweave-0.8.15/scripts/acceptance/g6_runner.py +0 -258
  194. execweave-0.8.15/scripts/acceptance/interrupt_guard.py +0 -88
  195. execweave-0.8.15/scripts/acceptance/processes.py +0 -207
  196. execweave-0.8.15/scripts/acceptance/reporting.py +0 -336
  197. execweave-0.8.15/scripts/acceptance/terminal_output.py +0 -242
  198. execweave-0.8.15/scripts/annotate_pytest_failures.py +0 -52
  199. execweave-0.8.15/scripts/audit_i18n_parity.py +0 -189
  200. execweave-0.8.15/scripts/check_claude_hook.py +0 -85
  201. execweave-0.8.15/scripts/check_claude_record_graph.py +0 -31
  202. execweave-0.8.15/scripts/check_codex_hook.py +0 -87
  203. execweave-0.8.15/scripts/check_conversation_records.py +0 -215
  204. execweave-0.8.15/scripts/check_correlation_graph.py +0 -80
  205. execweave-0.8.15/scripts/check_inference_gateway_cli.py +0 -155
  206. execweave-0.8.15/scripts/check_model_runtime_cli.py +0 -268
  207. execweave-0.8.15/scripts/check_openai_compatible_cli.py +0 -152
  208. execweave-0.8.15/scripts/check_release_stage_integrity.py +0 -79
  209. execweave-0.8.15/scripts/check_semantic_graph.py +0 -33
  210. execweave-0.8.15/scripts/check_viewer_js.py +0 -35
  211. execweave-0.8.15/scripts/check_wheel_install.py +0 -80
  212. execweave-0.8.15/scripts/check_windows_launchers.py +0 -120
  213. execweave-0.8.15/scripts/dashboard_acceptance.py +0 -49
  214. execweave-0.8.15/scripts/emit_claude_hook_smoke.py +0 -57
  215. execweave-0.8.15/scripts/emit_codex_hook_smoke.py +0 -201
  216. execweave-0.8.15/scripts/emit_cursor_hook_smoke.py +0 -67
  217. execweave-0.8.15/scripts/emit_opencode_plugin_smoke.py +0 -70
  218. execweave-0.8.15/scripts/make_semantic_smoke.py +0 -83
  219. execweave-0.8.15/scripts/measure_graph_metrics.py +0 -932
  220. execweave-0.8.15/scripts/ollama_interactive_acceptance.py +0 -88
  221. execweave-0.8.15/scripts/ollama_visible_acceptance.py +0 -33
  222. execweave-0.8.15/scripts/owned_cleanup_acceptance.py +0 -164
  223. execweave-0.8.15/scripts/probe_provider_capability.py +0 -167
  224. execweave-0.8.15/scripts/python_native_acceptance.py +0 -52
  225. execweave-0.8.15/scripts/sync_i18n_nav.py +0 -145
  226. execweave-0.8.15/src/execweave/live_view_script_d.py +0 -47
  227. execweave-0.8.15/tests/dashboard_readability_fixture.py +0 -232
  228. execweave-0.8.15/tests/fixtures/codex_multi_agent/PROVENANCE.md +0 -38
  229. execweave-0.8.15/tests/fixtures/codex_multi_agent/hook-payloads.json +0 -105
  230. execweave-0.8.15/tests/fixtures/codex_multi_agent/rollout-main.jsonl +0 -77
  231. execweave-0.8.15/tests/fixtures/hooks/README.md +0 -33
  232. execweave-0.8.15/tests/fixtures/hooks/claude.json +0 -35
  233. execweave-0.8.15/tests/fixtures/hooks/codex.json +0 -40
  234. execweave-0.8.15/tests/fixtures/hooks/cursor.json +0 -51
  235. execweave-0.8.15/tests/fixtures/hooks/manifest.json +0 -49
  236. execweave-0.8.15/tests/fixtures/hooks/opencode.json +0 -30
  237. execweave-0.8.15/tests/multi_agent_run_fixture.py +0 -210
  238. execweave-0.8.15/tests/test_acceptance_browser_diagnostics_e2e.py +0 -138
  239. execweave-0.8.15/tests/test_acceptance_conpty_selection.py +0 -43
  240. execweave-0.8.15/tests/test_acceptance_interrupt_guard.py +0 -65
  241. execweave-0.8.15/tests/test_acceptance_owned_processes.py +0 -112
  242. execweave-0.8.15/tests/test_acceptance_required_capabilities.py +0 -64
  243. execweave-0.8.15/tests/test_acceptance_terminal_output.py +0 -79
  244. execweave-0.8.15/tests/test_acceptance_visible_pipe.py +0 -47
  245. execweave-0.8.15/tests/test_agent_bootstrap.py +0 -259
  246. execweave-0.8.15/tests/test_agent_message_viewer.py +0 -138
  247. execweave-0.8.15/tests/test_agent_node_labels.py +0 -165
  248. execweave-0.8.15/tests/test_agent_said_panel.py +0 -92
  249. execweave-0.8.15/tests/test_agent_topology_evidence.py +0 -439
  250. execweave-0.8.15/tests/test_agent_trace_lifecycle.py +0 -82
  251. execweave-0.8.15/tests/test_agent_trace_viewer_visibility.py +0 -72
  252. execweave-0.8.15/tests/test_agy_windows_wire_acceptance.py +0 -302
  253. execweave-0.8.15/tests/test_analysis.py +0 -178
  254. execweave-0.8.15/tests/test_anthropic.py +0 -248
  255. execweave-0.8.15/tests/test_antigravity_agent_collaboration.py +0 -161
  256. execweave-0.8.15/tests/test_antigravity_child_panel_policy.py +0 -166
  257. execweave-0.8.15/tests/test_antigravity_child_transcript_tools.py +0 -158
  258. execweave-0.8.15/tests/test_antigravity_cursor_launch.py +0 -142
  259. execweave-0.8.15/tests/test_antigravity_field_run_regressions.py +0 -280
  260. execweave-0.8.15/tests/test_antigravity_history_replay.py +0 -233
  261. execweave-0.8.15/tests/test_antigravity_identity_topology.py +0 -112
  262. execweave-0.8.15/tests/test_antigravity_invocation_archive.py +0 -237
  263. execweave-0.8.15/tests/test_antigravity_lifecycle.py +0 -54
  264. execweave-0.8.15/tests/test_antigravity_linkage_projection.py +0 -98
  265. execweave-0.8.15/tests/test_antigravity_multi_conversation_isolation.py +0 -316
  266. execweave-0.8.15/tests/test_antigravity_official_contract.py +0 -157
  267. execweave-0.8.15/tests/test_antigravity_role_path_fallback.py +0 -249
  268. execweave-0.8.15/tests/test_antigravity_root_child_history_v2.py +0 -173
  269. execweave-0.8.15/tests/test_antigravity_subagent_transcript_linkage.py +0 -398
  270. execweave-0.8.15/tests/test_antigravity_trace_capability_cli.py +0 -48
  271. execweave-0.8.15/tests/test_auto_specialized.py +0 -380
  272. execweave-0.8.15/tests/test_auto_specialized_ollama_two_phase.py +0 -230
  273. execweave-0.8.15/tests/test_backends.py +0 -21
  274. execweave-0.8.15/tests/test_claude_adapter.py +0 -284
  275. execweave-0.8.15/tests/test_claude_child_transcript_tools.py +0 -240
  276. execweave-0.8.15/tests/test_claude_delegation.py +0 -121
  277. execweave-0.8.15/tests/test_claude_full_fidelity.py +0 -163
  278. execweave-0.8.15/tests/test_claude_hook_contract.py +0 -313
  279. execweave-0.8.15/tests/test_claude_hook_metadata.py +0 -60
  280. execweave-0.8.15/tests/test_claude_hook_viewer.py +0 -101
  281. execweave-0.8.15/tests/test_claude_model_observer.py +0 -393
  282. execweave-0.8.15/tests/test_claude_record.py +0 -198
  283. execweave-0.8.15/tests/test_cleanup_finalizer_identity.py +0 -31
  284. execweave-0.8.15/tests/test_codex_adapter.py +0 -222
  285. execweave-0.8.15/tests/test_codex_archive_full_fidelity.py +0 -224
  286. execweave-0.8.15/tests/test_codex_child_panel_policy.py +0 -375
  287. execweave-0.8.15/tests/test_codex_conversation_isolation.py +0 -94
  288. execweave-0.8.15/tests/test_codex_full_fidelity.py +0 -193
  289. execweave-0.8.15/tests/test_codex_hook_global_fail_open.py +0 -99
  290. execweave-0.8.15/tests/test_codex_hook_lifecycle.py +0 -177
  291. execweave-0.8.15/tests/test_codex_hook_partial_capture.py +0 -248
  292. execweave-0.8.15/tests/test_codex_interrupt_contract.py +0 -73
  293. execweave-0.8.15/tests/test_codex_message_diagnostics.py +0 -186
  294. execweave-0.8.15/tests/test_codex_message_transport_diagnostics.py +0 -184
  295. execweave-0.8.15/tests/test_codex_nickname_path_fallback.py +0 -134
  296. execweave-0.8.15/tests/test_codex_plain_routed_agent_message.py +0 -87
  297. execweave-0.8.15/tests/test_codex_real_multi_agent_conversation.py +0 -474
  298. execweave-0.8.15/tests/test_codex_record.py +0 -187
  299. execweave-0.8.15/tests/test_codex_reducer_command.py +0 -83
  300. execweave-0.8.15/tests/test_codex_rollout_structures.py +0 -234
  301. execweave-0.8.15/tests/test_codex_rollout_trace.py +0 -393
  302. execweave-0.8.15/tests/test_codex_routing_native_identity.py +0 -44
  303. execweave-0.8.15/tests/test_collector.py +0 -43
  304. execweave-0.8.15/tests/test_command.py +0 -76
  305. execweave-0.8.15/tests/test_condense.py +0 -154
  306. execweave-0.8.15/tests/test_conversation_access.py +0 -276
  307. execweave-0.8.15/tests/test_conversation_agent_focus.py +0 -158
  308. execweave-0.8.15/tests/test_conversation_agent_isolation.py +0 -117
  309. execweave-0.8.15/tests/test_conversation_identity_merge.py +0 -491
  310. execweave-0.8.15/tests/test_conversation_message_observation_dedupe.py +0 -346
  311. execweave-0.8.15/tests/test_conversation_provider_parity.py +0 -479
  312. execweave-0.8.15/tests/test_conversation_root_authority.py +0 -40
  313. execweave-0.8.15/tests/test_correlation.py +0 -404
  314. execweave-0.8.15/tests/test_correlation_canonical_path.py +0 -76
  315. execweave-0.8.15/tests/test_correlation_checker.py +0 -75
  316. execweave-0.8.15/tests/test_correlation_process_exe.py +0 -83
  317. execweave-0.8.15/tests/test_cross_provider_agent_trace.py +0 -306
  318. execweave-0.8.15/tests/test_cursor_adapter.py +0 -162
  319. execweave-0.8.15/tests/test_cursor_delegation.py +0 -91
  320. execweave-0.8.15/tests/test_cursor_full_fidelity.py +0 -268
  321. execweave-0.8.15/tests/test_cursor_hook_contract.py +0 -127
  322. execweave-0.8.15/tests/test_cursor_hook_fail_open.py +0 -60
  323. execweave-0.8.15/tests/test_cursor_ollama_session_lifecycle.py +0 -176
  324. execweave-0.8.15/tests/test_cursor_record.py +0 -82
  325. execweave-0.8.15/tests/test_cursor_task_linkage.py +0 -96
  326. execweave-0.8.15/tests/test_d003_fast_reparent.py +0 -134
  327. execweave-0.8.15/tests/test_dagre_semantic_pipeline.py +0 -254
  328. execweave-0.8.15/tests/test_dashboard_acceptance_relative_output_e2e.py +0 -36
  329. execweave-0.8.15/tests/test_dashboard_acceptance_reporting.py +0 -60
  330. execweave-0.8.15/tests/test_dashboard_camera_scheduler_e2e.py +0 -299
  331. execweave-0.8.15/tests/test_dashboard_favicon.py +0 -8
  332. execweave-0.8.15/tests/test_dashboard_file_activity_filter.py +0 -30
  333. execweave-0.8.15/tests/test_dashboard_gif_export_e2e.py +0 -108
  334. execweave-0.8.15/tests/test_dashboard_information_architecture.py +0 -251
  335. execweave-0.8.15/tests/test_dashboard_initial_fit_readability_e2e.py +0 -107
  336. execweave-0.8.15/tests/test_dashboard_node_drag_camera_e2e.py +0 -67
  337. execweave-0.8.15/tests/test_dashboard_readability_e2e.py +0 -407
  338. execweave-0.8.15/tests/test_dashboard_round_fold_state_e2e.py +0 -258
  339. execweave-0.8.15/tests/test_dashboard_simplification.py +0 -220
  340. execweave-0.8.15/tests/test_dashboard_ux_and_hook_projection.py +0 -383
  341. execweave-0.8.15/tests/test_delegation_viewer.py +0 -209
  342. execweave-0.8.15/tests/test_evidence_grade.py +0 -72
  343. execweave-0.8.15/tests/test_execution_viewer.py +0 -112
  344. execweave-0.8.15/tests/test_external_endpoints_all_providers.py +0 -169
  345. execweave-0.8.15/tests/test_fidelity.py +0 -335
  346. execweave-0.8.15/tests/test_filesystem_resilience.py +0 -235
  347. execweave-0.8.15/tests/test_focus.py +0 -139
  348. execweave-0.8.15/tests/test_fold_budget_setting.py +0 -121
  349. execweave-0.8.15/tests/test_full_fidelity.py +0 -91
  350. execweave-0.8.15/tests/test_g5_hardening_contract.py +0 -39
  351. execweave-0.8.15/tests/test_g6_owned_parity_contract.py +0 -133
  352. execweave-0.8.15/tests/test_graph.py +0 -333
  353. execweave-0.8.15/tests/test_graph_arrange_constraints_e2e.py +0 -111
  354. execweave-0.8.15/tests/test_graph_clear_focus_e2e.py +0 -126
  355. execweave-0.8.15/tests/test_graph_edge_routing_e2e.py +0 -168
  356. execweave-0.8.15/tests/test_graph_lane_separation_e2e.py +0 -170
  357. execweave-0.8.15/tests/test_graph_node_sizing_e2e.py +0 -288
  358. execweave-0.8.15/tests/test_graph_ops.py +0 -131
  359. execweave-0.8.15/tests/test_hook_fixture_corpus.py +0 -150
  360. execweave-0.8.15/tests/test_http_proxy.py +0 -261
  361. execweave-0.8.15/tests/test_http_proxy_request_phase.py +0 -121
  362. execweave-0.8.15/tests/test_http_proxy_response_memory.py +0 -154
  363. execweave-0.8.15/tests/test_http_proxy_streaming.py +0 -116
  364. execweave-0.8.15/tests/test_i18n_readme_policy.py +0 -49
  365. execweave-0.8.15/tests/test_inference_endpoint_identity.py +0 -147
  366. execweave-0.8.15/tests/test_inference_gateway.py +0 -155
  367. execweave-0.8.15/tests/test_inference_gateway_full_fidelity.py +0 -411
  368. execweave-0.8.15/tests/test_inference_identity.py +0 -78
  369. execweave-0.8.15/tests/test_integrity.py +0 -112
  370. execweave-0.8.15/tests/test_litellm_callback.py +0 -189
  371. execweave-0.8.15/tests/test_live.py +0 -220
  372. execweave-0.8.15/tests/test_live_auth.py +0 -176
  373. execweave-0.8.15/tests/test_live_dashboard.py +0 -31
  374. execweave-0.8.15/tests/test_live_dashboard_js.py +0 -48
  375. execweave-0.8.15/tests/test_live_delta.py +0 -179
  376. execweave-0.8.15/tests/test_live_logs_export.py +0 -93
  377. execweave-0.8.15/tests/test_live_theme.py +0 -11
  378. execweave-0.8.15/tests/test_lmstudio_auto_specialized.py +0 -149
  379. execweave-0.8.15/tests/test_local_runtime_live_capture.py +0 -185
  380. execweave-0.8.15/tests/test_model_runtime.py +0 -226
  381. execweave-0.8.15/tests/test_model_runtime_full_fidelity.py +0 -218
  382. execweave-0.8.15/tests/test_ollama_interactive_acceptance.py +0 -269
  383. execweave-0.8.15/tests/test_ollama_interactive_terminal_semantics.py +0 -76
  384. execweave-0.8.15/tests/test_ollama_panel_policy.py +0 -89
  385. execweave-0.8.15/tests/test_ollama_serve_runtime_integration.py +0 -293
  386. execweave-0.8.15/tests/test_ollama_visible_acceptance.py +0 -254
  387. execweave-0.8.15/tests/test_openai_compatible.py +0 -307
  388. execweave-0.8.15/tests/test_opencode_adapter.py +0 -72
  389. execweave-0.8.15/tests/test_opencode_event_contract.py +0 -246
  390. execweave-0.8.15/tests/test_opencode_event_lifecycle.py +0 -57
  391. execweave-0.8.15/tests/test_opencode_full_fidelity.py +0 -137
  392. execweave-0.8.15/tests/test_opencode_identity_unification.py +0 -87
  393. execweave-0.8.15/tests/test_opencode_plugin.py +0 -41
  394. execweave-0.8.15/tests/test_opencode_record.py +0 -90
  395. execweave-0.8.15/tests/test_opencode_task_session_linkage.py +0 -125
  396. execweave-0.8.15/tests/test_overhead_benchmark.py +0 -84
  397. execweave-0.8.15/tests/test_per_agent_conversation_default.py +0 -157
  398. execweave-0.8.15/tests/test_pr25_premerge_hardening_contract.py +0 -57
  399. execweave-0.8.15/tests/test_pr25_premerge_hardening_e2e.py +0 -411
  400. execweave-0.8.15/tests/test_pro6_audit_regressions.py +0 -228
  401. execweave-0.8.15/tests/test_process_tree_layout.py +0 -208
  402. execweave-0.8.15/tests/test_provider_capability.py +0 -202
  403. execweave-0.8.15/tests/test_provider_conversation_evidence.py +0 -304
  404. execweave-0.8.15/tests/test_provider_conversation_history_integrity.py +0 -335
  405. execweave-0.8.15/tests/test_provider_dashboard_contract.py +0 -401
  406. execweave-0.8.15/tests/test_provider_lifecycle.py +0 -225
  407. execweave-0.8.15/tests/test_provider_neutral_viewer_semantics.py +0 -190
  408. execweave-0.8.15/tests/test_pypi_0812_regressions.py +0 -171
  409. execweave-0.8.15/tests/test_pypi_0813_cleanup.py +0 -382
  410. execweave-0.8.15/tests/test_python_native_acceptance.py +0 -107
  411. execweave-0.8.15/tests/test_relay_prompt_live_e2e.py +0 -179
  412. execweave-0.8.15/tests/test_release_stage_integrity_version_guard.py +0 -112
  413. execweave-0.8.15/tests/test_rule_pack.py +0 -153
  414. execweave-0.8.15/tests/test_schema.py +0 -18
  415. execweave-0.8.15/tests/test_scope.py +0 -54
  416. execweave-0.8.15/tests/test_semantic.py +0 -277
  417. execweave-0.8.15/tests/test_shared_injected_context_scope.py +0 -90
  418. execweave-0.8.15/tests/test_single_agent_barycenter.py +0 -261
  419. execweave-0.8.15/tests/test_strace_backend.py +0 -202
  420. execweave-0.8.15/tests/test_stream_assembly.py +0 -380
  421. execweave-0.8.15/tests/test_threat_model.py +0 -202
  422. execweave-0.8.15/tests/test_tool_traffic_e2e.py +0 -138
  423. execweave-0.8.15/tests/test_top_detached.py +0 -180
  424. execweave-0.8.15/tests/test_v063_features.py +0 -132
  425. execweave-0.8.15/tests/test_v064_live_auto_integrations.py +0 -124
  426. execweave-0.8.15/tests/test_v064_live_evidence.py +0 -250
  427. execweave-0.8.15/tests/test_v069_dashboard_release.py +0 -145
  428. execweave-0.8.15/tests/test_v079_review_e2e.py +0 -184
  429. execweave-0.8.15/tests/test_v079_review_regressions.py +0 -105
  430. execweave-0.8.15/tests/test_v083_release_gate_p2.py +0 -150
  431. execweave-0.8.15/tests/test_validate.py +0 -113
  432. execweave-0.8.15/tests/test_version.py +0 -7
  433. execweave-0.8.15/tests/test_viewer.py +0 -345
  434. execweave-0.8.15/tests/test_viewer_agent_isolation_e2e.py +0 -885
  435. execweave-0.8.15/tests/test_viewer_child_authority.py +0 -22
  436. execweave-0.8.15/tests/test_viewer_content_inspector.py +0 -248
  437. execweave-0.8.15/tests/test_viewer_limits.py +0 -115
  438. execweave-0.8.15/tests/test_viewer_projection.py +0 -412
  439. execweave-0.8.15/tests/test_visual_ux_readability.py +0 -256
  440. execweave-0.8.15/tests/test_windows_codex_agy_display_repair.py +0 -220
  441. execweave-0.8.15/tests/test_workflow.py +0 -94
  442. execweave-0.8.15/tools/verify_metrics_tool.py +0 -104
  443. {execweave-0.8.15 → execweave-0.8.17}/.gitignore +0 -0
  444. {execweave-0.8.15 → execweave-0.8.17}/LICENSE +0 -0
  445. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/__main__.py +0 -0
  446. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/_conversation_records_core.py +0 -0
  447. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/_http_proxy_base.py +0 -0
  448. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/_http_proxy_bounded.py +0 -0
  449. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/_http_proxy_stage.py +0 -0
  450. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/agent_bootstrap.py +0 -0
  451. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/agent_topology.py +0 -0
  452. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/agent_trace.py +0 -0
  453. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/agy_preview_sanitize.py +0 -0
  454. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/analysis.py +0 -0
  455. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/anthropic.py +0 -0
  456. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/anthropic_cli.py +0 -0
  457. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/anthropic_full_fidelity.py +0 -0
  458. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_adapter.py +0 -0
  459. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_adapter_base.py +0 -0
  460. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_full_fidelity.py +0 -0
  461. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_full_fidelity_base.py +0 -0
  462. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
  463. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_hook_cli.py +0 -0
  464. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_record.py +0 -0
  465. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_subagent_linkage.py +0 -0
  466. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/antigravity_trace_capability.py +0 -0
  467. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/backends.py +0 -0
  468. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/benchmark.py +0 -0
  469. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_adapter.py +0 -0
  470. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_child_transcript.py +0 -0
  471. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_delegation.py +0 -0
  472. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_full_fidelity.py +0 -0
  473. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_hook_cli.py +0 -0
  474. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_hook_contract.py +0 -0
  475. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_model_observer.py +0 -0
  476. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/claude_record.py +0 -0
  477. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cli.py +0 -0
  478. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_adapter.py +0 -0
  479. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_conversation.py +0 -0
  480. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_full_fidelity.py +0 -0
  481. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_hook_cli.py +0 -0
  482. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_hook_entry.py +0 -0
  483. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_hook_lifecycle.py +0 -0
  484. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_message_diagnostics.py +0 -0
  485. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_message_transport_diagnostics.py +0 -0
  486. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_record.py +0 -0
  487. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_rollout_structures.py +0 -0
  488. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_rollout_trace.py +0 -0
  489. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/codex_rollout_trace_base.py +0 -0
  490. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/command.py +0 -0
  491. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/content_evidence.py +0 -0
  492. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/content_store.py +0 -0
  493. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_archive.py +0 -0
  494. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_message_identity.py +0 -0
  495. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview.py +0 -0
  496. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_antigravity.py +0 -0
  497. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_claude.py +0 -0
  498. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_codex.py +0 -0
  499. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_common.py +0 -0
  500. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_generic.py +0 -0
  501. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_lines.py +0 -0
  502. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_preview_transcript.py +0 -0
  503. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_records.py +0 -0
  504. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_records_antigravity.py +0 -0
  505. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_records_codex.py +0 -0
  506. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_records_common.py +0 -0
  507. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/conversation_records_ollama.py +0 -0
  508. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/correlation.py +0 -0
  509. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_adapter.py +0 -0
  510. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_delegation.py +0 -0
  511. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_delegation_base.py +0 -0
  512. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_full_fidelity.py +0 -0
  513. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_hook_cli.py +0 -0
  514. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_hook_contract.py +0 -0
  515. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/cursor_record.py +0 -0
  516. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/dashboard_shell.py +0 -0
  517. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/entry.py +0 -0
  518. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/evidence_availability.py +0 -0
  519. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/evidence_grade.py +0 -0
  520. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/fidelity.py +0 -0
  521. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/filesystem.py +0 -0
  522. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/focus.py +0 -0
  523. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/graph.py +0 -0
  524. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/graph_ops.py +0 -0
  525. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/http_proxy.py +0 -0
  526. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/http_proxy_cli.py +0 -0
  527. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/inference_gateway.py +0 -0
  528. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/inference_gateway_cli.py +0 -0
  529. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/inference_gateway_full_fidelity.py +0 -0
  530. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/inference_identity.py +0 -0
  531. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/inference_identity_cli.py +0 -0
  532. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/integrity.py +0 -0
  533. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/integrity_cli.py +0 -0
  534. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/litellm_callback.py +0 -0
  535. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/litellm_callback_cli.py +0 -0
  536. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live.py +0 -0
  537. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_extra_style.py +0 -0
  538. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_markup.py +0 -0
  539. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_readability.py +0 -0
  540. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_script_a.py +0 -0
  541. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_script_b.py +0 -0
  542. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/live_view_style.py +0 -0
  543. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/model_runtime.py +0 -0
  544. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/model_runtime_cli.py +0 -0
  545. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/model_runtime_full_fidelity.py +0 -0
  546. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/openai_compatible.py +0 -0
  547. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/openai_compatible_cli.py +0 -0
  548. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/openai_compatible_full_fidelity.py +0 -0
  549. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_adapter.py +0 -0
  550. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_event_contract.py +0 -0
  551. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_full_fidelity.py +0 -0
  552. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_hook_cli.py +0 -0
  553. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_plugin_cli.py +0 -0
  554. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_record.py +0 -0
  555. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/opencode_task_linkage.py +0 -0
  556. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/overhead_benchmark.py +0 -0
  557. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/provider_capability.py +0 -0
  558. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/provider_lifecycle.py +0 -0
  559. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/provider_record.py +0 -0
  560. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/rule_pack.py +0 -0
  561. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/rule_pack_cli.py +0 -0
  562. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/scalability_benchmark.py +0 -0
  563. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/schema.py +0 -0
  564. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/scope.py +0 -0
  565. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/semantic.py +0 -0
  566. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/sink.py +0 -0
  567. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/strace_backend.py +0 -0
  568. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/stream_assembly.py +0 -0
  569. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/theme.py +0 -0
  570. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/top_cli.py +0 -0
  571. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/validate.py +0 -0
  572. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/vendor/dagre.min.js +0 -0
  573. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/view_cli.py +0 -0
  574. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer.py +0 -0
  575. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel.py +0 -0
  576. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
  577. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_claude.py +0 -0
  578. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_codex.py +0 -0
  579. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_cursor.py +0 -0
  580. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_default.py +0 -0
  581. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_ollama.py +0 -0
  582. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_opencode.py +0 -0
  583. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_agent_panel_registry.py +0 -0
  584. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_content_inspector.py +0 -0
  585. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_dashboard_hardening.py +0 -0
  586. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_external_endpoints.py +0 -0
  587. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_limits.py +0 -0
  588. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_live_layout.py +0 -0
  589. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_projection.py +0 -0
  590. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_projection_base.py +0 -0
  591. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/viewer_semantic_projection.py +0 -0
  592. {execweave-0.8.15 → execweave-0.8.17}/src/execweave/workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execweave
3
- Version: 0.8.15
3
+ Version: 0.8.17
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
@@ -42,10 +42,12 @@ Requires-Python: >=3.10
42
42
  Requires-Dist: psutil>=5.9
43
43
  Requires-Dist: watchdog>=4.0
44
44
  Provides-Extra: dev
45
+ Requires-Dist: pillow>=10.0; extra == 'dev'
45
46
  Requires-Dist: pytest>=8.0; extra == 'dev'
46
47
  Requires-Dist: pywinpty<4,>=3.0.5; (platform_system == 'Windows') and extra == 'dev'
47
48
  Requires-Dist: ruff<0.17,>=0.16; extra == 'dev'
48
49
  Provides-Extra: e2e
50
+ Requires-Dist: pillow>=10.0; extra == 'e2e'
49
51
  Requires-Dist: playwright>=1.44; extra == 'e2e'
50
52
  Requires-Dist: pywinpty<4,>=3.0.5; (platform_system == 'Windows') and extra == 'e2e'
51
53
  Provides-Extra: release
@@ -188,6 +190,15 @@ The dashboard is designed to keep large, multi-agent runs inspectable without ch
188
190
  - **Large-run folding:** high-cardinality node types can collapse older members while keeping them inspectable.
189
191
  - **Selection-focused layout:** selecting an agent or runtime object de-emphasizes unrelated graph traffic.
190
192
 
193
+ **Download GIF** saves the graph viewport as it appeared while this Dashboard page
194
+ was open and visible, including labels, folding, camera changes, and elapsed time
195
+ (sampled at up to 10 frames per second). It excludes the inspector and logs. A
196
+ reopened finished run has no recorded screen history and exports a still image.
197
+ Keep the viewport size fixed for a consistent frame; resizing adds padding rather
198
+ than rescaling older frames. Recording stops with an explicit message if the page
199
+ is hidden during a live run, rendering is paused, or the 64 MB recording limit is
200
+ reached; it never substitutes an animation reconstructed from the final graph.
201
+
191
202
  You can tune large-run rendering with:
192
203
 
193
204
  ```text
@@ -133,6 +133,15 @@ The dashboard is designed to keep large, multi-agent runs inspectable without ch
133
133
  - **Large-run folding:** high-cardinality node types can collapse older members while keeping them inspectable.
134
134
  - **Selection-focused layout:** selecting an agent or runtime object de-emphasizes unrelated graph traffic.
135
135
 
136
+ **Download GIF** saves the graph viewport as it appeared while this Dashboard page
137
+ was open and visible, including labels, folding, camera changes, and elapsed time
138
+ (sampled at up to 10 frames per second). It excludes the inspector and logs. A
139
+ reopened finished run has no recorded screen history and exports a still image.
140
+ Keep the viewport size fixed for a consistent frame; resizing adds padding rather
141
+ than rescaling older frames. Recording stops with an explicit message if the page
142
+ is hidden during a live run, rendering is paused, or the 64 MB recording limit is
143
+ reached; it never substitutes an animation reconstructed from the final graph.
144
+
136
145
  You can tune large-run rendering with:
137
146
 
138
147
  ```text
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "execweave"
7
- # ExecWeave v0.8.15 release metadata
8
- version = "0.8.15"
7
+ # ExecWeave v0.8.17 release metadata
8
+ version = "0.8.17"
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"
@@ -44,6 +44,7 @@ dependencies = [
44
44
  [project.optional-dependencies]
45
45
  dev = [
46
46
  "pytest>=8.0",
47
+ "pillow>=10.0",
47
48
  "ruff>=0.16,<0.17",
48
49
  "pywinpty>=3.0.5,<4; platform_system == 'Windows'",
49
50
  ]
@@ -55,6 +56,7 @@ release = [
55
56
  # development install stays small; CI installs it and requires the checks to run.
56
57
  e2e = [
57
58
  "playwright>=1.44",
59
+ "pillow>=10.0",
58
60
  "pywinpty>=3.0.5,<4; platform_system == 'Windows'",
59
61
  ]
60
62
 
@@ -93,6 +95,14 @@ execweave-scalability = "execweave.scalability_benchmark:main"
93
95
  [tool.hatch.build.targets.wheel]
94
96
  packages = ["src/execweave"]
95
97
 
98
+ [tool.hatch.build.targets.sdist]
99
+ include = [
100
+ "/src/execweave",
101
+ "/pyproject.toml",
102
+ "/README.md",
103
+ "/LICENSE",
104
+ ]
105
+
96
106
  [tool.pytest.ini_options]
97
107
  testpaths = ["tests"]
98
108
  pythonpath = ["src"]
@@ -1,3 +1,3 @@
1
1
  """ExecWeave runtime graph package."""
2
2
 
3
- __version__ = "0.8.15"
3
+ __version__ = "0.8.17"
@@ -6,8 +6,9 @@ from typing import Any
6
6
  from .live_view import LIVE_HTML as _BASE_LIVE_HTML
7
7
  from .viewer_agent_panel import inject_agent_panel
8
8
  from .viewer_dashboard_clean import fold_budget_bootstrap, inject_live_dashboard_clean
9
- from .viewer_limits import resolve_viewer_limits, viewer_limits_bootstrap
10
9
  from .viewer_dashboard_focus import inject_live_dashboard_focus
10
+ from .viewer_dashboard_pr70 import inject_pr70_dashboard_repairs
11
+ from .viewer_limits import resolve_viewer_limits, viewer_limits_bootstrap
11
12
  from .viewer_live_layout import inject_live_dashboard_layout
12
13
 
13
14
 
@@ -70,6 +71,7 @@ def _build_dashboard_html() -> str:
70
71
  html = _preserve_semantic_layout_constraints(html)
71
72
  html = _preserve_semantic_arrange(html)
72
73
  html = _route_ordinary_edges_from_final_positions(html)
74
+ html = inject_pr70_dashboard_repairs(html)
73
75
  return _align_agent_panel_topology(inject_agent_panel(_guard_compact_live_snapshot(html)))
74
76
 
75
77
 
@@ -115,4 +117,4 @@ def render_static_dashboard_html(
115
117
  "<body>",
116
118
  '<body>\n<!-- unified dashboard: theme is owned by the visible #theme-toggle control -->',
117
119
  1,
118
- )
120
+ )
@@ -14,6 +14,8 @@ from urllib.error import HTTPError, URLError
14
14
  from urllib.parse import urlsplit, urlunsplit
15
15
  from urllib.request import Request, urlopen
16
16
 
17
+ from .runtime_endpoint_availability import windows_exclusive_endpoint_available
18
+
17
19
  from .model_runtime import (
18
20
  append_model_runtime_records,
19
21
  llamacpp_models_to_events,
@@ -214,6 +216,49 @@ def _probe_spec(command: list[str]) -> _ProbeSpec | None:
214
216
  return None
215
217
 
216
218
 
219
+ @dataclass(frozen=True)
220
+ class _LiveProbeAdmission:
221
+ # Prepared before the child (and any managed relay) is launched. A grace
222
+ # period is a scheduling aid, never evidence of endpoint ownership.
223
+ spec: _ProbeSpec | None
224
+
225
+
226
+ def prepare_live_specialized_probe(command: list[str]) -> _LiveProbeAdmission:
227
+ """Do not attach an already listening or uncertain endpoint to a new run.
228
+
229
+ A refused connection establishes absence at this pre-launch boundary. A
230
+ Windows connect timeout requires independent exclusive-bind proof for every
231
+ resolved loopback address; a timeout alone never authorizes a probe. Other
232
+ unknown/denied states abstain. This affects automatic catalog polling only,
233
+ not command execution or explicit request/response capture.
234
+ """
235
+ if not os.environ.get(_SEMANTIC_ENV):
236
+ return _LiveProbeAdmission(None)
237
+ spec = _probe_spec(command)
238
+ if spec is None:
239
+ return _LiveProbeAdmission(None)
240
+ address = urlsplit(spec.endpoint)
241
+ try:
242
+ with socket.create_connection(
243
+ (str(address.hostname), int(address.port or 80)),
244
+ timeout=_PROBE_TIMEOUT_SECONDS,
245
+ ):
246
+ pass
247
+ except ConnectionRefusedError:
248
+ return _LiveProbeAdmission(spec)
249
+ except TimeoutError:
250
+ if windows_exclusive_endpoint_available(str(address.hostname), int(address.port or 80)):
251
+ return _LiveProbeAdmission(spec)
252
+ except OSError:
253
+ pass
254
+ print(
255
+ f"ExecWeave {spec.runtime} probe: endpoint {spec.endpoint} was not "
256
+ "proven unused before launch; automatic catalog evidence is disabled.",
257
+ file=sys.stderr,
258
+ )
259
+ return _LiveProbeAdmission(None)
260
+
261
+
217
262
  def _get_json(url: str, *, timeout: float) -> dict[str, object]:
218
263
  request = Request(url, headers={"Accept": "application/json"})
219
264
  with urlopen(request, timeout=timeout) as response:
@@ -462,10 +507,18 @@ def auto_specialized_launch(
462
507
 
463
508
 
464
509
  @contextmanager
465
- def auto_specialized_probe(command: list[str]) -> Iterator[None]:
466
- """Run supported local specialized probes without affecting command execution."""
510
+ def auto_specialized_probe(
511
+ command: list[str],
512
+ *,
513
+ admission: _LiveProbeAdmission | None = None,
514
+ ) -> Iterator[None]:
515
+ """Poll a prepared launch, or an explicitly requested library observation.
516
+
517
+ RuntimeCollector always supplies pre-launch admission. A direct library
518
+ caller without admission retains the explicit endpoint-observation API.
519
+ """
467
520
  configured_sidecar = os.environ.get(_SEMANTIC_ENV)
468
- spec = _probe_spec(command)
521
+ spec = admission.spec if admission is not None else _probe_spec(command)
469
522
  if not configured_sidecar or spec is None:
470
523
  yield
471
524
  return
@@ -16,6 +16,7 @@ from .auto_specialized import (
16
16
  auto_specialized_launch,
17
17
  auto_specialized_probe,
18
18
  prepare_post_command_specialized_probe,
19
+ prepare_live_specialized_probe,
19
20
  run_post_command_specialized_probe,
20
21
  )
21
22
  from .command import resolve_launch_command
@@ -209,6 +210,7 @@ class RuntimeCollector:
209
210
  collector_error_type: str | None = None
210
211
  workload_terminated_due_to_collector_error = False
211
212
  subreaper_previous: bool | None = None
213
+ live_probe_admission = prepare_live_specialized_probe(command)
212
214
  post_command_probe = prepare_post_command_specialized_probe(command)
213
215
  try:
214
216
  if watcher is not None:
@@ -235,7 +237,7 @@ class RuntimeCollector:
235
237
  if snapshot is not None:
236
238
  self._record_process_start(snapshot, parent=session, relation="LAUNCHED")
237
239
 
238
- with auto_specialized_probe(command):
240
+ with auto_specialized_probe(command, admission=live_probe_admission):
239
241
  while process.poll() is None:
240
242
  self._sample_process_tree(root)
241
243
  time.sleep(self.poll_interval)
@@ -549,6 +549,11 @@ class _LiveState:
549
549
  else _inject_final_theme(render_graph_html(final_graph))
550
550
  )
551
551
  with self._lock:
552
+ # The last browser poll may precede the collector's final batch.
553
+ # Drain complete runtime/semantic records for raw-log and evidence
554
+ # counters before publishing FINISHED. The canonical graph below,
555
+ # not the provisional accumulator, remains the graph authority.
556
+ self._refresh_incremental_locked()
552
557
  self._final_graph = final_graph
553
558
  self._final_html = rendered_final
554
559
  self._finished = True
@@ -563,6 +568,11 @@ class _LiveState:
563
568
  "edges_added": [],
564
569
  "edges_updated": [],
565
570
  "terminal": True,
571
+ # A counts-only terminal delta loses unpolled nodes/edges and
572
+ # canonical identity/metadata changes. Reconcile in this same
573
+ # sequence-visible response, before the client stops polling.
574
+ # Use the normal projection and payload budget, as on reconnect.
575
+ "final_graph": self._snapshot_from_accumulator_locked(),
566
576
  }
567
577
  if not _within_live_payload_budget(node_count, edge_count):
568
578
  terminal["live_payload_compact"] = True
@@ -1,7 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import re
4
-
5
3
  from .live_view_extra_style import LIVE_EXTRA_STYLE
6
4
  from .live_view_markup import LIVE_MARKUP
7
5
  from .live_view_process_layout import LIVE_PROCESS_LAYOUT_SCRIPT
@@ -15,21 +13,6 @@ from .viewer_agent_panel import inject_agent_panel
15
13
  from .viewer_dashboard_hardening_v2 import harden_dashboard_html
16
14
 
17
15
 
18
- _SAFE_GIF_LZW = (
19
- "function lzw(indices,minCodeSize=8){"
20
- "const clear=1<<minCodeSize,end=clear+1,out=[];"
21
- "let buffer=0,bits=0;const codeSize=minCodeSize+1;"
22
- "const chunk=Math.max(1,(1<<codeSize)-clear-8);"
23
- "const emit=code=>{buffer|=code<<bits;bits+=codeSize;"
24
- "while(bits>=8){out.push(buffer&255);buffer>>>=8;bits-=8}};"
25
- "if(!indices.length)emit(clear);"
26
- "for(let start=0;start<indices.length;start+=chunk){"
27
- "emit(clear);const stop=Math.min(indices.length,start+chunk);"
28
- "for(let i=start;i<stop;i++)emit(indices[i])}"
29
- "emit(end);if(bits>0)out.push(buffer&255);return out}"
30
- )
31
-
32
-
33
16
  def _restore_live_safety_contracts(html: str) -> str:
34
17
  """Preserve live-view safety contracts while retiring legacy final-page swapping."""
35
18
  html = html.replace(
@@ -62,16 +45,6 @@ def _restore_live_safety_contracts(html: str) -> str:
62
45
  1,
63
46
  )
64
47
 
65
- html, lzw_count = re.subn(
66
- r"function lzw\(indices,minCodeSize=8\)\{.*?\}\nfunction gifBlocks",
67
- _SAFE_GIF_LZW + "\nfunction gifBlocks",
68
- html,
69
- count=1,
70
- flags=re.DOTALL,
71
- )
72
- if lzw_count != 1:
73
- raise RuntimeError("live GIF encoder patch target not found")
74
-
75
48
  open_final_button = '<button id="open-final" type="button">Open final graph</button>'
76
49
  if open_final_button not in html:
77
50
  raise RuntimeError("legacy final action patch target not found")
@@ -254,16 +254,17 @@ function execweaveLayoutDirectedGraph(topo){
254
254
  }
255
255
  try{
256
256
  const graph=new engine.graphlib.Graph();
257
- graph.setGraph({rankdir:'LR',nodesep:EXECWEAVE_DAG_GAP,ranksep:48,marginx:16,marginy:16,edgesep:16});
257
+ graph.setGraph({rankdir:'LR',nodesep:EXECWEAVE_DAG_GAP,ranksep:48,marginx:0,marginy:16,edgesep:16});
258
258
  graph.setDefaultEdgeLabel(()=>({}));
259
259
  const ids=[];
260
- for(const id of topo.spec.keys()){
260
+ for(const id of [...topo.spec.keys()].sort()){
261
261
  if(!nodeById.has(id))continue;
262
262
  graph.setNode(id,{width:execweaveWidthOf(id),height:execweaveHeightOf(id)});
263
263
  ids.push(id);
264
264
  }
265
265
  const seen=new Set();
266
- for(const edge of edgeById.values()){
266
+ for(const edge of [...edgeById.values()].sort((a,b)=>edgeId(a).localeCompare(edgeId(b)))){
267
+ if(typeof execweaveIsStopped==='function'&&execweaveIsStopped(edge))continue;
267
268
  if(!topo.spec.has(edge.source)||!topo.spec.has(edge.target)||edge.source===edge.target)continue;
268
269
  const key=execweaveEdgeKey(edge.source,edge.target);
269
270
  if(seen.has(key))continue;
@@ -301,74 +302,24 @@ function execweaveRestoreSemanticLayoutConstraints(topo,preferred,dagrePlacement
301
302
  const nodes=[...nodeById.values()],edges=[...edgeById.values()];
302
303
  const componentOf=execweaveComponents(nodes,edges);
303
304
 
304
- // X constraint: Semantic lanes define bounding constraints.
305
- // Dynamically propagate corridor lower bounds across semantic ranks so Dagre
306
- // horizontal positions are retained within their architectural corridors.
307
- const laneRank = {
308
- runtime: 0,
309
- root: 1,
310
- agent: 2,
311
- model: 3,
312
- tool: 4,
313
- file: 5,
314
- endpoint: 6,
315
- other: 6
316
- };
317
-
318
- // Group non-process nodes by semantic rank
319
- const nodesByRank = new Map();
320
- for (const [id, before] of preferred) {
321
- const node = nodeById.get(id);
322
- if (!node) continue;
323
- const type = String(node.type || '').toLowerCase();
324
- if (type === 'process' || type === 'session' || type === 'runtime') continue;
325
- const lane = topo.spec.get(id)?.lane || before.lane || 'other';
326
- const rank = laneRank[lane] ?? 3;
327
- if (!nodesByRank.has(rank)) nodesByRank.set(rank, []);
328
- nodesByRank.get(rank).push(id);
329
- }
330
-
331
- // Handle process-like nodes first (pinned to process-tree coordinates)
332
- let maxProcessRight = 0;
333
- for (const [id, before] of preferred) {
334
- const after = topo.spec.get(id), node = nodeById.get(id);
335
- if (!after || !node) continue;
336
- const type = String(node.type || '').toLowerCase();
337
- if (type === 'process' || type === 'session' || type === 'runtime') {
338
- if (Number.isFinite(before.x)) after.x = before.x;
339
- const pw = topo.width?.get(id) || (typeof execweaveWidthOf === 'function' ? execweaveWidthOf(id) : 160);
340
- const px = Number.isFinite(after.x) ? after.x : 0;
341
- maxProcessRight = Math.max(maxProcessRight, px + pw);
342
- }
343
- }
344
-
345
- // Propagate corridor lower bounds across ranks:
346
- // rank 1 (root) < rank 2 (agent) < rank 3 (model) < rank 4 (tool) < rank 5 (file) < rank 6 (endpoint)
347
- let minAllowedX = maxProcessRight;
348
- for (let r = 1; r <= 6; r++) {
349
- const ids = nodesByRank.get(r) || [];
350
- if (!ids.length) continue;
351
- let rankMaxX = minAllowedX;
352
- for (const id of ids) {
353
- const after = topo.spec.get(id);
354
- const before = preferred.get(id);
355
- const dagreX = dagrePlacement.get(id)?.x;
356
- const laneX = topo.laneX && Number.isFinite(topo.laneX[after?.lane]) ? topo.laneX[after.lane] : before?.x;
357
- if (!after) continue;
358
-
359
- const isBundledTarget = edges.some(e => e.target === id && topo.bundleByEdge?.get(edgeId(e))?.size > 1);
360
- const candidateX = isBundledTarget && Number.isFinite(laneX) ? laneX : dagreX;
361
-
362
- if (Number.isFinite(candidateX) && candidateX >= minAllowedX) {
363
- after.x = candidateX;
364
- } else if (Number.isFinite(before?.x) && before.x >= minAllowedX) {
365
- after.x = before.x;
366
- } else {
367
- after.x = minAllowedX;
368
- }
369
- rankMaxX = Math.max(rankMaxX, after.x);
370
- }
371
- minAllowedX = rankMaxX + 1;
305
+ // Constrain X to measured semantic corridors. Dagre supplies ordering and route
306
+ // control points; process-tree depth is retained within the runtime corridor.
307
+ // All render paths consume these final coordinates, including Arrange.
308
+ let floor=-Infinity;
309
+ for(const [id,before] of preferred){
310
+ const after=topo.spec.get(id),node=nodeById.get(id);
311
+ if(!after||!node||!isProcess(node))continue;
312
+ after.x=before.x;
313
+ floor=Math.max(floor,after.x+(topo.width?.get(id)||EXECWEAVE_NODE_W)+PROCESS_COL_GAP);
314
+ }
315
+ for(const lane of ['root','agent','model','tool','file','endpoint','other']){
316
+ const ids=[...topo.spec.keys()].filter(id=>topo.spec.get(id)?.lane===lane&&!isProcess(nodeById.get(id)));
317
+ if(!ids.length)continue;
318
+ const laneX=Number.isFinite(topo.laneX?.[lane])?topo.laneX[lane]:Math.min(...ids.map(id=>preferred.get(id).x));
319
+ const x=Math.max(laneX,Number.isFinite(floor)?floor:laneX);
320
+ let right=x;
321
+ for(const id of ids){const after=topo.spec.get(id);after.x=x;right=Math.max(right,x+(topo.width?.get(id)||EXECWEAVE_NODE_W))}
322
+ floor=right+PROCESS_COL_GAP;
372
323
  }
373
324
 
374
325
  // Y constraint: Dagre coordinates optimize positions within semantic lane/component bounds
@@ -462,9 +413,15 @@ function execweaveRestoreSemanticLayoutConstraints(topo,preferred,dagrePlacement
462
413
  return{value,members,minX,maxX,minY,maxY,w:maxX-minX,h:maxY-minY};
463
414
  }).filter(box=>Number.isFinite(box.minX));
464
415
 
416
+ // Use an aspect-balanced shelf width for disconnected components instead of
417
+ // forcing every component wider than half a short spine onto its own row.
418
+ // Component shapes/ordering stay intact; this is packing, not raw graph repair.
419
+ const columns=Math.max(1,Math.ceil(Math.sqrt(compBoxes.length)));
420
+ const widest=compBoxes.reduce((width,box)=>Math.max(width,box.w),0);
421
+ const packingWidth=Math.max(spineWidth,columns*widest+(columns-1)*bandGap);
465
422
  let cursorX=spineLeft,cursorY=spineFloor+bandGap,rowHeight=0;
466
423
  for(const box of compBoxes){
467
- if(cursorX>spineLeft&&cursorX+box.w>spineLeft+spineWidth){
424
+ if(cursorX>spineLeft&&cursorX+box.w>spineLeft+packingWidth){
468
425
  cursorX=spineLeft;cursorY+=rowHeight+bandGap;rowHeight=0;
469
426
  }
470
427
  const shiftX=cursorX-box.minX,shiftY=cursorY-box.minY;
@@ -565,7 +522,13 @@ function execweaveRouteFromPoints(edge,points){
565
522
  return{d,labelX:labelPoint.x,labelY:labelPoint.y-8,kind:execweaveIsSpawn(edge)?'spawn':(forward?'forward':'reverse'),bundle:null};
566
523
  }
567
524
  const execweaveBuildTopologyBase=execweaveBuildTopology;
568
- execweaveBuildTopology=function(){return execweaveApplyDirectedGraph(execweaveLayoutRelated(execweaveLayoutProcessTree(execweaveBuildTopologyBase())))};
525
+ execweaveBuildTopology=function(){
526
+ // Width/height and lane helpers must see THIS build, never the previous graph.
527
+ const topo=execweaveBuildTopologyBase(),prior=execweaveTopology;
528
+ execweaveTopology=topo;
529
+ try{return execweaveApplyDirectedGraph(execweaveLayoutRelated(execweaveLayoutProcessTree(topo)))}
530
+ finally{execweaveTopology=prior}
531
+ };
569
532
  if(typeof window!=='undefined'){
570
533
  window.execweaveLayoutDirectedGraph=execweaveLayoutDirectedGraph;
571
534
  window.execweaveSeparateOverlappingNodes=execweaveSeparateOverlappingNodes;
@@ -653,13 +616,7 @@ function execweaveWriteDirectedPositions(topo){
653
616
  const next=new Map();
654
617
  for(const id of nodeById.keys()){
655
618
  const spec=topo.spec.get(id);
656
- const packed=topo.secondaryPackedIds?.has(id);
657
- const laneX=(topo.laneX&&spec?.lane&&Number.isFinite(topo.laneX[spec.lane]))?topo.laneX[spec.lane]:spec?.x;
658
- // Connected semantic lanes retain their established X contract. Only
659
- // disconnected components use the final 2D packing X; forcing those back
660
- // to the lane origin would stack every orphan node on the same rectangle.
661
- const initialX=packed?spec?.x:laneX;
662
- next.set(id,spec?{x:initialX,y:spec.y}:execweaveDesiredPosition(id));
619
+ next.set(id,spec?{x:spec.x,y:spec.y}:execweaveDesiredPosition(id));
663
620
  }
664
621
  positions=next;layerRows=new Map();
665
622
  for(const [id,p] of positions){
@@ -673,20 +630,19 @@ function execweaveWriteDirectedPositions(topo){
673
630
  for(const edge of edgeById.values())updateEdgeElement(edge);
674
631
  svg.classList.toggle('execweave-crowded',!!topo.crowded);
675
632
  }
676
- const execweaveFullLayoutBase=fullLayout;
677
- fullLayout=function(){
678
- const prior=positions;
679
- const incoming=[...nodeById.keys()].some(id=>!prior.has(id));
680
- if(prior.size&&!incoming){execweaveFullLayoutBase();return}
633
+ function execweaveInstallFinalLayout(priorY){
681
634
  execweaveTopology=execweaveBuildTopology();
682
635
  execweaveWriteDirectedPositions(execweaveTopology);
636
+ if(priorY.size&&typeof execweaveRestorePriorYUnlessWorse==='function'){
637
+ execweaveRestorePriorYUnlessWorse(priorY,execweaveTopology);
638
+ window.__execweavePr70.paint();
639
+ }
640
+ }
641
+ fullLayout=function(){
642
+ execweaveInstallFinalLayout(new Map([...positions].map(([id,p])=>[id,p.y])));
683
643
  };
684
- const execweavePlaceAddedBase=placeAddedNodes;
685
- placeAddedNodes=function(ids){
686
- const incoming=(ids||[]).filter(id=>nodeById.has(id)&&!positions.has(id));
687
- if(!incoming.length){execweavePlaceAddedBase(ids);return}
688
- execweaveTopology=execweaveBuildTopology();
689
- execweaveWriteDirectedPositions(execweaveTopology);
644
+ placeAddedNodes=function(_ids){
645
+ execweaveInstallFinalLayout(new Map([...positions].map(([id,p])=>[id,p.y])));
690
646
  };
691
647
  })();
692
648
  """.strip()
@@ -12,7 +12,7 @@ function updateJumpLatest(){jumpLatest.hidden=!latestNodeId||latestInsideSafeZon
12
12
  function userTookCamera(){if(cameraMode!=='manual')setCameraMode('manual',{apply:false})}
13
13
  function zoomBy(factor){userTookCamera();const box=svg.getBoundingClientRect(),mx=box.width/2,my=box.height/2,old=transform.scale,nextScale=Math.min(4,Math.max(.07,old*factor)),gx=(mx-transform.x)/old,gy=(my-transform.y)/old;animateTo({x:mx-gx*nextScale,y:my-gy*nextScale,scale:nextScale},140)}
14
14
  function applySearch(){const q=search.value.trim().toLowerCase(),matched=new Set();document.querySelectorAll('.node').forEach(el=>{const ok=!q||el.dataset.search.includes(q);el.classList.toggle('dim',!ok);if(ok)matched.add(el.dataset.id)});document.querySelectorAll('.edge').forEach(el=>{const keep=!q||matched.has(el.dataset.source)||matched.has(el.dataset.target)||el.dataset.relation.includes(q);el.classList.toggle('dim',!keep)})}
15
- async function poll(){try{const response=await fetch(`/live.json?after=${liveSequence}`,{cache:'no-store'});if(!response.ok)throw new Error(String(response.status));const data=await response.json();if(data.kind==='snapshot'){liveSequence=Number(data.sequence)||0;setSnapshot(data.graph||{});}else if(data.kind==='delta'){if(Number(data.base_sequence)!==liveSequence){liveSequence=-1;setStatus('RESYNCING','resyncing');setTimeout(poll,0);return}for(const update of data.updates||[]){if(Number(update.sequence)!==liveSequence+1){liveSequence=-1;setStatus('RESYNCING','resyncing');setTimeout(poll,0);return}applyDelta(update);liveSequence=Number(update.sequence)}if(!(data.updates||[]).length)liveSequence=Number(data.sequence)||liveSequence;}else if(data.kind==='noop'){liveSequence=Number(data.sequence)||liveSequence;updateStats(data);}window.__execweaveDashboard?.onPayload?.(data);updateEvidence(data);const finished=!!data.live_finished;setStatus(finished?'FINISHED':(protectedMode?'PROTECTED':'LIVE'),finished?'finished':protectedMode?'reconnecting':'');if(finished){window.__execweaveDashboard?.onFinished?.();return}}catch(_){setStatus('RECONNECTING','reconnecting')}setTimeout(poll,500)}
15
+ async function poll(){try{const response=await fetch(`/live.json?after=${liveSequence}`,{cache:'no-store'});if(!response.ok)throw new Error(String(response.status));const data=await response.json();if(data.kind==='snapshot'){liveSequence=Number(data.sequence)||0;setSnapshot(data.graph||{});}else if(data.kind==='delta'){if(Number(data.base_sequence)!==liveSequence){liveSequence=-1;setStatus('RESYNCING','resyncing');setTimeout(poll,0);return}for(const update of data.updates||[]){if(Number(update.sequence)!==liveSequence+1){liveSequence=-1;setStatus('RESYNCING','resyncing');setTimeout(poll,0);return}if(update.terminal&&update.final_graph)setSnapshot(update.final_graph);else applyDelta(update);liveSequence=Number(update.sequence)}if(!(data.updates||[]).length)liveSequence=Number(data.sequence)||liveSequence;}else if(data.kind==='noop'){liveSequence=Number(data.sequence)||liveSequence;updateStats(data);}window.__execweaveDashboard?.onPayload?.(data);updateEvidence(data);const finished=!!data.live_finished;setStatus(finished?'FINISHED':(protectedMode?'PROTECTED':'LIVE'),finished?'finished':protectedMode?'reconnecting':'');if(finished){window.__execweaveDashboard?.onFinished?.();return}}catch(_){setStatus('RECONNECTING','reconnecting')}setTimeout(poll,500)}
16
16
  svg.onpointerdown=e=>{if(e.target.closest?.('.node'))return;userTookCamera();stopAnimation();pan={x:e.clientX,y:e.clientY,tx:transform.x,ty:transform.y,travelled:false};svg.classList.add('panning');svg.setPointerCapture(e.pointerId)};svg.onpointermove=e=>{if(!pan)return;if(Math.abs(e.clientX-pan.x)>3||Math.abs(e.clientY-pan.y)>3)pan.travelled=true;transform.x=pan.tx+e.clientX-pan.x;transform.y=pan.ty+e.clientY-pan.y;applyTransform();updateJumpLatest()};svg.onpointerup=e=>{const dragged=!!pan?.travelled;pan=null;svg.classList.remove('panning');try{svg.releasePointerCapture(e.pointerId)}catch(_){}if(!dragged&&!e.target.closest?.('.node'))window.__execweaveClearFocus?.()};svg.addEventListener('wheel',e=>{e.preventDefault();userTookCamera();stopAnimation();const rect=svg.getBoundingClientRect(),mx=e.clientX-rect.left,my=e.clientY-rect.top,old=transform.scale,next=Math.min(4,Math.max(.07,old*Math.exp(-e.deltaY*.0012))),gx=(mx-transform.x)/old,gy=(my-transform.y)/old;transform.scale=next;transform.x=mx-gx*next;transform.y=my-gy*next;applyTransform();updateJumpLatest()},{passive:false});
17
17
  function focusRawLogEvent(event){const target=event?.target?.id,source=event?.source?.id;if(target&&nodeById.has(target)){selectNode(target,{syncLog:false});focusNode(target);return}if(source&&nodeById.has(source)){selectNode(source,{syncLog:false});focusNode(source)}}
18
18
  // Focus is only exitable if something offers the exit. The control appears with the
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from .viewer_gif import GIF_SCRIPT
4
+
5
+ LIVE_SCRIPT_D = r"""
6
+ (()=>{
7
+ const core=window.__execweaveCore;
8
+ if(!core)return;
9
+ const structuredList=document.getElementById('activity-list'),rawLog=document.getElementById('raw-log'),rawRows=document.getElementById('raw-rows'),activityCount=document.getElementById('activity-count'),filterGroup=document.querySelector('.filter-group'),finishedActions=document.getElementById('finished-actions'),replayButton=document.getElementById('replay-run'),gifButton=document.getElementById('download-gif'),openFinalButton=document.getElementById('open-final'),details=document.getElementById('details'),detailsEmpty=document.getElementById('details-empty');
10
+ const MAX_RAW=640;
11
+ let rawEntries=[],logMode='structured',finishedShown=false,finalHtmlCache=null,replaying=false;
12
+ function rawId(entry){return`raw-${entry.stream||'events'}-${entry.line??'x'}-${entry.event?.event_id||entry.event?.sequence||''}`}
13
+ function rawTime(event){const value=event?.timestamp;if(!value)return'—';const d=new Date(value);if(Number.isNaN(d.getTime()))return String(value);return d.toLocaleTimeString([],{hour:'2-digit',minute:'2-digit',second:'2-digit',fractionalSecondDigits:3})}
14
+ function rawEventType(event){return String(event?.event_type||event?.type||'event')}
15
+ function rawRelation(event){return String(event?.relation||'—')}
16
+ function rawSummary(event){try{return JSON.stringify(event)}catch(_){return String(event)}}
17
+ function setRawEntries(items){rawEntries=(items||[]).slice(-MAX_RAW);renderRaw(false)}
18
+ function addRawEntries(items){if(!items?.length)return;rawEntries.push(...items);if(rawEntries.length>MAX_RAW)rawEntries=rawEntries.slice(-MAX_RAW);renderRaw(logMode==='raw')}
19
+ function findGraphEdge(event){const source=event?.source?.id,target=event?.target?.id,relation=event?.relation;if(!source||!target||!relation)return null;const visible=[...document.querySelectorAll('.edge')].find(el=>el.dataset.source===source&&el.dataset.target===target&&el.dataset.relation===String(relation).toLowerCase());return visible?.dataset.edgeId||null}
20
+ function showRaw(entry){const event=entry.event||{};detailsEmpty.hidden=true;details.innerHTML='';const title=document.createElement('div');title.className='current-title';title.textContent=rawEventType(event);const sub=document.createElement('div');sub.className='current-sub';sub.textContent=`${entry.stream||'events.jsonl'} line ${entry.line??'—'} · ${rawRelation(event)}`;const pre=document.createElement('pre');pre.textContent=JSON.stringify(event,null,2);const raw=document.createElement('details');raw.className='raw-toggle';raw.open=true;const summary=document.createElement('summary');summary.textContent='Raw event JSON';raw.append(summary,pre);details.append(title,sub,raw);const nodeMap=new Map();for(const node of(core.getGraph()?.nodes||[])){if(node?.id)nodeMap.set(node.id,node);for(const key of['viewer_member_ids','viewer_agent_member_ids'])for(const member of(node?.attributes?.[key]||[]))nodeMap.set(String(member),node)}const targets=document.createElement('div');targets.className='raw-target-actions';for(const entity of [event.source,event.target]){if(!entity?.id||!nodeMap.has(entity.id))continue;const node=nodeMap.get(entity.id);const button=document.createElement('button');button.type='button';button.textContent=`Inspect ${node.type||'node'}${node.name?` · ${node.name}`:''}`;button.addEventListener('click',()=>core.selectNode(node.id,{syncLog:false}));targets.appendChild(button)}if(targets.childElementCount)details.appendChild(targets)}
21
+ function selectRaw(entry,row){document.querySelectorAll('.raw-row.selected').forEach(el=>el.classList.remove('selected'));row.classList.add('selected');const edge=findGraphEdge(entry.event);if(edge)core.selectEdge(edge,{syncLog:false});showRaw(entry)}
22
+ function renderRaw(scrollLatest=false){rawRows.replaceChildren();activityCount.textContent=logMode==='raw'?`${rawEntries.length} raw event${rawEntries.length===1?'':'s'}`:`${core.getActivities().length} transition${core.getActivities().length===1?'':'s'}`;if(!rawEntries.length){const empty=document.createElement('div');empty.className='empty-activity';empty.textContent='Waiting for runtime or semantic activity…';rawRows.appendChild(empty);return}for(const entry of rawEntries){const row=document.createElement('div');row.className='raw-row';row.dataset.rawId=rawId(entry);const line=document.createElement('span');line.className='raw-line';line.textContent=String(entry.line??'—');const time=document.createElement('span');time.className='raw-time';time.textContent=rawTime(entry.event);const event=document.createElement('span');event.className='raw-event';event.textContent=rawEventType(entry.event);const relation=document.createElement('span');relation.className='raw-relation';relation.textContent=rawRelation(entry.event);const json=document.createElement('span');json.className='raw-json';json.textContent=rawSummary(entry.event);json.title=json.textContent;row.append(line,time,event,relation,json);row.onclick=()=>selectRaw(entry,row);rawRows.appendChild(row)}if(scrollLatest)rawRows.lastElementChild?.scrollIntoView({block:'nearest'})}
23
+ function setLogMode(mode){logMode=mode==='raw'?'raw':'structured';document.querySelectorAll('[data-log-mode]').forEach(button=>button.classList.toggle('active',button.dataset.logMode===logMode));structuredList.hidden=logMode==='raw';rawLog.hidden=logMode!=='raw';filterGroup.hidden=logMode==='raw';if(logMode==='raw')renderRaw(false);else activityCount.textContent=`${core.getActivities().length} transition${core.getActivities().length===1?'':'s'}`}
24
+ document.querySelectorAll('[data-log-mode]').forEach(button=>button.onclick=()=>setLogMode(button.dataset.logMode));
25
+ function onPayload(data){observeGifPayload(data);if(data.kind==='snapshot')setRawEntries(data.raw_events||[]);else if(data.kind==='delta'){const added=[];for(const update of data.updates||[])added.push(...(update.raw_events_added||[]));addRawEntries(added)}}
26
+ function timelineItems(){const activities=core.getActivities().filter(item=>item.edgeId||item.nodeId);return activities.length?activities:[]}
27
+ function revealNode(id){if(!id)return;document.querySelector(`.node[data-id="${CSS.escape(id)}"]`)?.classList.remove('replay-hidden')}
28
+ function revealEdge(id){if(!id)return;const edge=document.querySelector(`.edge[data-edge-id="${CSS.escape(id)}"]`);edge?.classList.remove('replay-hidden');document.querySelector(`.label[data-edge-id="${CSS.escape(id)}"]`)?.classList.remove('replay-hidden');if(edge){revealNode(edge.dataset.source);revealNode(edge.dataset.target)}}
29
+ function restoreReplayDom(){document.querySelectorAll('.replay-hidden,.replay-active').forEach(el=>el.classList.remove('replay-hidden','replay-active'))}
30
+ const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
31
+ async function replayRun(){if(replaying)return;const timeline=timelineItems();if(!timeline.length)return;replaying=true;replayButton.disabled=true;restoreReplayDom();document.querySelectorAll('.node,.edge,.label').forEach(el=>el.classList.add('replay-hidden'));core.setCameraMode('fit');const delay=Math.max(55,Math.min(180,7000/Math.max(1,timeline.length)));for(const item of timeline){document.querySelectorAll('.replay-active').forEach(el=>el.classList.remove('replay-active'));if(item.edgeId){revealEdge(item.edgeId);document.querySelector(`.edge[data-edge-id="${CSS.escape(item.edgeId)}"]`)?.classList.add('replay-active')}if(item.nodeId){revealNode(item.nodeId);document.querySelector(`.node[data-id="${CSS.escape(item.nodeId)}"]`)?.classList.add('replay-active')}core.markLatest(item.nodeId||null,item.edgeId||null);await sleep(delay)}await sleep(380);restoreReplayDom();const last=timeline[timeline.length-1];core.markLatest(last.nodeId||null,last.edgeId||null);replaying=false;replayButton.disabled=false}
32
+ """ + GIF_SCRIPT + r"""
33
+ async function prepareFinalView(){try{const response=await fetch('/final',{cache:'no-store'});if(!response.ok)throw new Error(String(response.status));finalHtmlCache=await response.text()}catch(_){finalHtmlCache=null}}
34
+ function openFinal(){if(!finalHtmlCache)return;document.open();document.write(finalHtmlCache);document.close()}
35
+ function onFinished(){if(finishedShown)return;finishedShown=true;finishedActions.hidden=false;prepareFinalView()}
36
+ replayButton.onclick=replayRun;gifButton.onclick=downloadGif;openFinalButton.onclick=openFinal;
37
+ window.__execweaveDashboard={onPayload,onFinished};
38
+ if(window.__execweaveStaticMode)onFinished();
39
+ })();
40
+ """
@@ -0,0 +1,44 @@
1
+ """Conservative Winsock fallback for a timed-out pre-launch loopback connect."""
2
+ from __future__ import annotations
3
+
4
+ import ipaddress
5
+ import socket
6
+ import sys
7
+ from contextlib import ExitStack
8
+
9
+
10
+ def windows_exclusive_endpoint_available(host: str, port: int) -> bool:
11
+ """Require exclusive binds, not a timeout, as evidence of unused addresses.
12
+
13
+ A short Windows connect can time out before an unused port reports refusal.
14
+ SO_EXCLUSIVEADDRUSE prevents taking over an existing bind. Every resolved
15
+ loopback address must be exclusively bindable at the same instant; sockets
16
+ are closed before the real relay/child starts. No listener is created and no
17
+ SO_REUSEADDR is enabled. This proves availability only at the launch boundary,
18
+ not ownership of an unrelated service started later.
19
+ """
20
+ exclusive = getattr(socket, 'SO_EXCLUSIVEADDRUSE', None)
21
+ if sys.platform != 'win32' or exclusive is None or not 0 < port <= 65535:
22
+ return False
23
+ try:
24
+ addresses = socket.getaddrinfo(host, port, type=socket.SOCK_STREAM,
25
+ proto=socket.IPPROTO_TCP)
26
+ seen = set()
27
+ with ExitStack() as stack:
28
+ for family, kind, protocol, _, address in addresses:
29
+ if family not in (socket.AF_INET, socket.AF_INET6):
30
+ return False
31
+ if not ipaddress.ip_address(address[0]).is_loopback:
32
+ return False
33
+ key = (family, address)
34
+ if key in seen:
35
+ continue
36
+ seen.add(key)
37
+ reservation = stack.enter_context(socket.socket(family, kind, protocol))
38
+ reservation.setsockopt(socket.SOL_SOCKET, exclusive, 1)
39
+ if family == socket.AF_INET6:
40
+ reservation.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1)
41
+ reservation.bind(address)
42
+ return bool(seen)
43
+ except (OSError, ValueError):
44
+ return False
@@ -69,6 +69,12 @@ class TerminalState:
69
69
 
70
70
  def apply_update(self, update: dict[str, object]) -> None:
71
71
  self.sequence = int(update.get("sequence", self.sequence) or self.sequence)
72
+ final_graph = update.get("final_graph")
73
+ if update.get("terminal") and isinstance(final_graph, dict):
74
+ # The web client and Top must consume the same authoritative final
75
+ # entities, including canonical identity replacement, before stopping.
76
+ self.apply_snapshot(final_graph, self.sequence)
77
+ return
72
78
  self.event_count = int(update.get("event_count", self.event_count) or 0)
73
79
  self.node_count = int(update.get("node_count", self.node_count) or 0)
74
80
  self.edge_count = int(update.get("edge_count", self.edge_count) or 0)
@@ -397,9 +397,4 @@ def inject_live_dashboard_clean(html: str) -> str:
397
397
  html = html[:render_index] + html[render_index:].replace(render_marker, render_replacement, 1)
398
398
  html = html.replace(_LIVE_CORE_EXPORT, _LIVE_CORE_EXPORT_CLEAN, 1)
399
399
  html = html.replace(_LIVE_NOOP_STATS, _LIVE_NOOP_STATS_CLEAN, 1)
400
- html = html.replace(
401
- "const graph=core.getGraph(),positions=core.getPositions(),steps=sortedGifSteps(graph);",
402
- "const graph=core.getDisplayGraph?.()||core.getGraph(),positions=core.getPositions(),steps=sortedGifSteps(graph);",
403
- 1,
404
- )
405
400
  return html