execweave 0.8.19__tar.gz → 0.8.20__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 (177) hide show
  1. {execweave-0.8.19 → execweave-0.8.20}/PKG-INFO +1 -1
  2. {execweave-0.8.19 → execweave-0.8.20}/pyproject.toml +2 -2
  3. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/__init__.py +1 -1
  4. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/_dashboard_shell_base.py +2 -0
  5. execweave-0.8.20/src/execweave/viewer_edge_decross.py +117 -0
  6. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_execution_flow_safety.py +16 -2
  7. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_layout_geometry.py +75 -1
  8. {execweave-0.8.19 → execweave-0.8.20}/.gitignore +0 -0
  9. {execweave-0.8.19 → execweave-0.8.20}/LICENSE +0 -0
  10. {execweave-0.8.19 → execweave-0.8.20}/README.md +0 -0
  11. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/__main__.py +0 -0
  12. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/_conversation_records_core.py +0 -0
  13. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/_http_proxy_base.py +0 -0
  14. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/_http_proxy_bounded.py +0 -0
  15. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/_http_proxy_stage.py +0 -0
  16. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/agent_bootstrap.py +0 -0
  17. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/agent_topology.py +0 -0
  18. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/agent_trace.py +0 -0
  19. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/agy_preview_sanitize.py +0 -0
  20. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/analysis.py +0 -0
  21. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/anthropic.py +0 -0
  22. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/anthropic_cli.py +0 -0
  23. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/anthropic_full_fidelity.py +0 -0
  24. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_adapter.py +0 -0
  25. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_adapter_base.py +0 -0
  26. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_full_fidelity.py +0 -0
  27. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_full_fidelity_base.py +0 -0
  28. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
  29. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_hook_cli.py +0 -0
  30. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_record.py +0 -0
  31. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_subagent_linkage.py +0 -0
  32. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/antigravity_trace_capability.py +0 -0
  33. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/auto_specialized.py +0 -0
  34. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/backends.py +0 -0
  35. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/benchmark.py +0 -0
  36. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_adapter.py +0 -0
  37. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_child_transcript.py +0 -0
  38. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_delegation.py +0 -0
  39. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_full_fidelity.py +0 -0
  40. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_hook_cli.py +0 -0
  41. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_hook_contract.py +0 -0
  42. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_model_observer.py +0 -0
  43. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/claude_record.py +0 -0
  44. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cli.py +0 -0
  45. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_adapter.py +0 -0
  46. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_conversation.py +0 -0
  47. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_full_fidelity.py +0 -0
  48. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_hook_cli.py +0 -0
  49. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_hook_entry.py +0 -0
  50. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_hook_lifecycle.py +0 -0
  51. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_message_diagnostics.py +0 -0
  52. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_message_transport_diagnostics.py +0 -0
  53. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_record.py +0 -0
  54. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_rollout_structures.py +0 -0
  55. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_rollout_trace.py +0 -0
  56. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/codex_rollout_trace_base.py +0 -0
  57. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/collector.py +0 -0
  58. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/command.py +0 -0
  59. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/content_evidence.py +0 -0
  60. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/content_store.py +0 -0
  61. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_archive.py +0 -0
  62. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_message_identity.py +0 -0
  63. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview.py +0 -0
  64. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_antigravity.py +0 -0
  65. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_claude.py +0 -0
  66. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_codex.py +0 -0
  67. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_common.py +0 -0
  68. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_generic.py +0 -0
  69. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_lines.py +0 -0
  70. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_preview_transcript.py +0 -0
  71. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_records.py +0 -0
  72. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_records_antigravity.py +0 -0
  73. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_records_codex.py +0 -0
  74. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_records_common.py +0 -0
  75. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/conversation_records_ollama.py +0 -0
  76. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/correlation.py +0 -0
  77. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_adapter.py +0 -0
  78. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_delegation.py +0 -0
  79. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_delegation_base.py +0 -0
  80. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_full_fidelity.py +0 -0
  81. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_hook_cli.py +0 -0
  82. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_hook_contract.py +0 -0
  83. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/cursor_record.py +0 -0
  84. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/dashboard_shell.py +0 -0
  85. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/entry.py +0 -0
  86. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/evidence_availability.py +0 -0
  87. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/evidence_grade.py +0 -0
  88. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/fidelity.py +0 -0
  89. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/filesystem.py +0 -0
  90. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/focus.py +0 -0
  91. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/graph.py +0 -0
  92. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/graph_ops.py +0 -0
  93. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/http_proxy.py +0 -0
  94. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/http_proxy_cli.py +0 -0
  95. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/inference_gateway.py +0 -0
  96. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/inference_gateway_cli.py +0 -0
  97. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/inference_gateway_full_fidelity.py +0 -0
  98. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/inference_identity.py +0 -0
  99. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/inference_identity_cli.py +0 -0
  100. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/integrity.py +0 -0
  101. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/integrity_cli.py +0 -0
  102. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/litellm_callback.py +0 -0
  103. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/litellm_callback_cli.py +0 -0
  104. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live.py +0 -0
  105. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_core.py +0 -0
  106. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view.py +0 -0
  107. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_extra_style.py +0 -0
  108. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_markup.py +0 -0
  109. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_process_layout.py +0 -0
  110. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_readability.py +0 -0
  111. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_script_a.py +0 -0
  112. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_script_b.py +0 -0
  113. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_script_c.py +0 -0
  114. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_script_d.py +0 -0
  115. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/live_view_style.py +0 -0
  116. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/model_runtime.py +0 -0
  117. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/model_runtime_cli.py +0 -0
  118. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/model_runtime_full_fidelity.py +0 -0
  119. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/openai_compatible.py +0 -0
  120. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/openai_compatible_cli.py +0 -0
  121. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/openai_compatible_full_fidelity.py +0 -0
  122. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_adapter.py +0 -0
  123. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_event_contract.py +0 -0
  124. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_full_fidelity.py +0 -0
  125. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_hook_cli.py +0 -0
  126. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_plugin_cli.py +0 -0
  127. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_record.py +0 -0
  128. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/opencode_task_linkage.py +0 -0
  129. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/overhead_benchmark.py +0 -0
  130. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/provider_capability.py +0 -0
  131. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/provider_lifecycle.py +0 -0
  132. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/provider_record.py +0 -0
  133. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/rule_pack.py +0 -0
  134. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/rule_pack_cli.py +0 -0
  135. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/runtime_endpoint_availability.py +0 -0
  136. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/scalability_benchmark.py +0 -0
  137. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/schema.py +0 -0
  138. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/scope.py +0 -0
  139. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/semantic.py +0 -0
  140. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/sink.py +0 -0
  141. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/strace_backend.py +0 -0
  142. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/stream_assembly.py +0 -0
  143. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/theme.py +0 -0
  144. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/top.py +0 -0
  145. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/top_cli.py +0 -0
  146. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/validate.py +0 -0
  147. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/vendor/dagre.min.js +0 -0
  148. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/view_cli.py +0 -0
  149. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer.py +0 -0
  150. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel.py +0 -0
  151. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
  152. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_claude.py +0 -0
  153. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_codex.py +0 -0
  154. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_cursor.py +0 -0
  155. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_default.py +0 -0
  156. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_ollama.py +0 -0
  157. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_opencode.py +0 -0
  158. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_agent_panel_registry.py +0 -0
  159. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_content_inspector.py +0 -0
  160. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_dashboard_clean.py +0 -0
  161. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_dashboard_focus.py +0 -0
  162. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_dashboard_hardening.py +0 -0
  163. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
  164. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_dashboard_pr70.py +0 -0
  165. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_execution_flow.py +0 -0
  166. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_external_endpoints.py +0 -0
  167. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_gif.py +0 -0
  168. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_layout_v2.py +0 -0
  169. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_layout_v2_detached.py +0 -0
  170. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_limits.py +0 -0
  171. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_live_layout.py +0 -0
  172. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_projection.py +0 -0
  173. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_projection_base.py +0 -0
  174. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_projection_bridges.py +0 -0
  175. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_semantic_projection.py +0 -0
  176. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/viewer_tool_mirror_identity.py +0 -0
  177. {execweave-0.8.19 → execweave-0.8.20}/src/execweave/workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execweave
3
- Version: 0.8.19
3
+ Version: 0.8.20
4
4
  Summary: Turn AI-agent runtime behavior into a local interactive execution graph.
5
5
  Project-URL: Homepage, https://github.com/Irish-kw/ExecWeave
6
6
  Project-URL: Repository, https://github.com/Irish-kw/ExecWeave
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "execweave"
7
- # ExecWeave v0.8.19 release metadata
8
- version = "0.8.19"
7
+ # ExecWeave v0.8.20 release metadata
8
+ version = "0.8.20"
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.19"
3
+ __version__ = "0.8.20"
@@ -8,6 +8,7 @@ from .viewer_agent_panel import inject_agent_panel
8
8
  from .viewer_dashboard_clean import fold_budget_bootstrap, inject_live_dashboard_clean
9
9
  from .viewer_dashboard_focus import inject_live_dashboard_focus
10
10
  from .viewer_dashboard_pr70 import inject_pr70_dashboard_repairs
11
+ from .viewer_edge_decross import inject_edge_decross
11
12
  from .viewer_execution_flow import inject_execution_flow
12
13
  from .viewer_execution_flow_safety import harden_execution_flow_projection
13
14
  from .viewer_layout_v2 import inject_layout_v2
@@ -78,6 +79,7 @@ def _build_dashboard_html() -> str:
78
79
  html = inject_pr70_dashboard_repairs(html)
79
80
  html = inject_layout_v2(html)
80
81
  html = inject_layout_v2_detached_cluster_policy(html)
82
+ html = inject_edge_decross(html)
81
83
  html = harden_execution_flow_projection(inject_execution_flow(html))
82
84
  return _align_agent_panel_topology(inject_agent_panel(_guard_compact_live_snapshot(html)))
83
85
 
@@ -0,0 +1,117 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ _STARTUP_SEAM = "applyTheme(initialTheme());applyTransform();poll();"
5
+
6
+ EDGE_DECROSS_SCRIPT = r"""
7
+ (function(){
8
+ if(typeof execweaveRoute!=='function'||typeof execweaveGeometry==='undefined')return;
9
+ const baseRoute=execweaveRoute;
10
+ const relation=edge=>String(edge?.relation||'').toUpperCase();
11
+ const nodeType=id=>String(typeof nodeById!=='undefined'?nodeById.get(id)?.type||'':'').toLowerCase();
12
+ const isNetworkEdge=edge=>relation(edge)==='CONNECTED_TO'||
13
+ nodeType(edge?.source)==='network_endpoint'||nodeType(edge?.target)==='network_endpoint';
14
+ const routePoints=edge=>{
15
+ const route=baseRoute(edge);
16
+ const points=route?.d?execweaveGeometry.polyline(route.d):null;
17
+ return{route,points};
18
+ };
19
+ const segments=points=>{
20
+ const result=[];
21
+ for(let i=1;i<(points?.length||0);i++)result.push({a:points[i-1],b:points[i]});
22
+ return result;
23
+ };
24
+ const crossesAny=(points,protectedSegments)=>{
25
+ for(let i=1;i<(points?.length||0);i++)for(const segment of protectedSegments)
26
+ if(execweaveGeometry.crosses(points[i-1],points[i],segment.a,segment.b))return true;
27
+ return false;
28
+ };
29
+
30
+ execweaveRoute=function(edge){
31
+ const {route,points}=routePoints(edge);
32
+ if(!route||!points||points.length<2||isNetworkEdge(edge)||route.kind==='bundle'||route.kind==='lifecycle-return')return route;
33
+ if(typeof edgeById==='undefined'||typeof positions==='undefined'||!execweaveTopology)return route;
34
+
35
+ const protectedSegments=[];
36
+ for(const peer of edgeById.values()){
37
+ if(edgeId(peer)===edgeId(edge)||!isNetworkEdge(peer))continue;
38
+ const peerPoints=routePoints(peer).points;
39
+ if(peerPoints?.length>=2)protectedSegments.push(...segments(peerPoints));
40
+ }
41
+ if(!protectedSegments.length||!crossesAny(points,protectedSegments))return route;
42
+
43
+ const boxes=[...positions]
44
+ .filter(([id])=>id!==edge.source&&id!==edge.target&&nodeById.has(id))
45
+ .map(([id,p])=>({
46
+ id,x:p.x,y:p.y,
47
+ w:execweaveTopology.width?.get(id)||execweaveWidthOf(id),
48
+ h:execweaveTopology.height?.get(id)||execweaveHeightOf(id),
49
+ }));
50
+ const detour=execweaveGeometry.avoidCrossings(points,boxes,protectedSegments,8);
51
+ if(!detour||detour.crossingsAvoided<=0||detour.points.length<2)return route;
52
+ const d=detour.points.map((point,index)=>`${index?'L':'M'} ${point.x} ${point.y}`).join(' ');
53
+ const label=detour.points[Math.floor(detour.points.length/2)];
54
+ return{
55
+ ...route,d,labelX:label.x,labelY:label.y-8,
56
+ geometryKind:'edge-decrossover',
57
+ edgeCrossingDetours:detour.detours,
58
+ protectedNetworkCrossingsAvoided:detour.crossingsAvoided,
59
+ };
60
+ };
61
+
62
+ if(typeof updateEdgeElement==='function'){
63
+ const updateBase=updateEdgeElement;
64
+ updateEdgeElement=function(edge){
65
+ // The existing PR70 wrapper already computes label placement and then clears
66
+ // it from rendered node boxes. Do not overwrite that cleared label position.
67
+ updateBase(edge);
68
+ const route=execweaveRoute(edge);
69
+ if(route?.geometryKind!=='edge-decrossover'||!route.d)return;
70
+ const els=edgeElements.get(edgeId(edge));if(!els)return;
71
+ // The base renderer normally sees the dynamically replaced execweaveRoute.
72
+ // Reapply only the path as a final authority guard; leave the label untouched.
73
+ els.visible.setAttribute('d',route.d);els.hit.setAttribute('d',route.d);
74
+ els.visible.dataset.geometryKind=route.geometryKind;
75
+ els.hit.dataset.geometryKind=route.geometryKind;
76
+ };
77
+ }
78
+
79
+ const renderedMetrics=()=>{
80
+ if(typeof positions==='undefined'||typeof edgeById==='undefined'||typeof nodeById==='undefined')return null;
81
+ const nodes=[...positions]
82
+ .filter(([id])=>nodeById.has(id))
83
+ .map(([id,p])=>({
84
+ id,x:p.x,y:p.y,
85
+ w:execweaveTopology?.width?.get(id)||execweaveWidthOf(id),
86
+ h:execweaveTopology?.height?.get(id)||execweaveHeightOf(id),
87
+ }));
88
+ const edges=[...edgeById.values()]
89
+ .filter(edge=>positions.has(edge.source)&&positions.has(edge.target))
90
+ .map(edge=>({...edge,d:execweaveRoute(edge).d}));
91
+ return execweaveGeometry.measure(nodes,edges);
92
+ };
93
+
94
+ // PR70's optimizer deliberately keeps its own pre-decrossover route family, but
95
+ // public metrics are a rendered-SVG diagnostic contract. Report the final paths
96
+ // users actually see so metric parity cannot drift after this local routing pass.
97
+ if(window.__execweavePr70&&typeof window.__execweavePr70.metrics==='function'){
98
+ const metricsBase=window.__execweavePr70.metrics.bind(window.__execweavePr70);
99
+ window.__execweavePr70.metrics=()=>renderedMetrics()||metricsBase();
100
+ window.__execweavePr70.crossingCount=()=>window.__execweavePr70.metrics().EDGE_CROSSINGS;
101
+ }
102
+
103
+ window.__execweaveEdgeDecross={
104
+ version:2,
105
+ routeFor:id=>{const edge=typeof edgeById!=='undefined'?edgeById.get(id):null;return edge?execweaveRoute(edge):null},
106
+ metrics:renderedMetrics,
107
+ };
108
+ })();
109
+ """.strip()
110
+
111
+
112
+ def inject_edge_decross(html: str) -> str:
113
+ """Prefer local route detours over moving nodes across network evidence edges."""
114
+
115
+ if html.count(_STARTUP_SEAM) != 1:
116
+ raise RuntimeError("edge-decrossover startup seam changed")
117
+ return html.replace(_STARTUP_SEAM, EDGE_DECROSS_SCRIPT + "\n" + _STARTUP_SEAM, 1)
@@ -26,9 +26,16 @@ _TARGETED_ACTIVATION = """ const resolvedOccurrences=occurrences.filter(occur
26
26
  if(!resolvedOccurrences.length)return display;"""
27
27
  _WAIT_AWARE_ACTIVATION = """ const providerObservedEdge=edge=>{
28
28
  const evidence=attrsOf(edge);
29
+ const eventTypes=Array.isArray(edge?.event_types)?edge.event_types:[];
30
+ const backends=Array.isArray(edge?.backends)?edge.backends:[];
31
+ const attributions=Array.isArray(edge?.attributions)?edge.attributions:[];
32
+ const lifecycle=Array.isArray(edge?.provider_lifecycle)?edge.provider_lifecycle:[];
29
33
  return edge?.viewer_only===true||Boolean(
30
34
  evidence.provider||evidence.evidence_source||evidence.attribution||
31
- evidence.provider_event||evidence.provider_event_type
35
+ evidence.provider_event||evidence.provider_event_type||
36
+ lifecycle.length||attributions.length||
37
+ backends.some(value=>String(value).toLowerCase()==='semantic')||
38
+ eventTypes.some(value=>String(value).toLowerCase().startsWith('semantic.'))
32
39
  );
33
40
  };
34
41
  const spawnEdges=rawEdges.filter(edge=>
@@ -92,9 +99,16 @@ _SAFE_DIRECT_ACTION_LOOP = """ for(const edge of rawEdges){
92
99
  const kind=DIRECT_ACTION_RELATIONS.get(relation(edge));
93
100
  if(!kind)continue;
94
101
  const evidence=attrsOf(edge);
102
+ const eventTypes=Array.isArray(edge?.event_types)?edge.event_types:[];
103
+ const backends=Array.isArray(edge?.backends)?edge.backends:[];
104
+ const attributions=Array.isArray(edge?.attributions)?edge.attributions:[];
105
+ const lifecycle=Array.isArray(edge?.provider_lifecycle)?edge.provider_lifecycle:[];
95
106
  const providerObserved=edge.viewer_only===true||Boolean(
96
107
  evidence.provider||evidence.evidence_source||evidence.attribution||
97
- evidence.provider_event||evidence.provider_event_type
108
+ evidence.provider_event||evidence.provider_event_type||
109
+ lifecycle.length||attributions.length||
110
+ backends.some(value=>String(value).toLowerCase()==='semantic')||
111
+ eventTypes.some(value=>String(value).toLowerCase().startsWith('semantic.'))
98
112
  );
99
113
  if(!providerObserved)continue;
100
114
  const owner=agentForAnchor(edge.source),target=agentForAnchor(edge.target);
@@ -87,6 +87,80 @@ const execweaveGeometry=(function(){
87
87
  return{points:out,detours,obstructedGuides:points.length-guides.length};
88
88
  }
89
89
 
90
+ function avoidCrossings(points,boxes,segments,clearance=7){
91
+ const protectedSegments=(Array.isArray(segments)?segments:[]).filter(segment=>
92
+ segment?.a&&segment?.b&&Number.isFinite(segment.a.x)&&Number.isFinite(segment.a.y)&&
93
+ Number.isFinite(segment.b.x)&&Number.isFinite(segment.b.y)&&
94
+ Math.hypot(segment.b.x-segment.a.x,segment.b.y-segment.a.y)>epsilon
95
+ );
96
+ if(!Array.isArray(points)||points.length<2||!protectedSegments.length){
97
+ return{points:Array.isArray(points)?points:[],detours:0,crossingsAvoided:0};
98
+ }
99
+ const nodeBoxes=Array.isArray(boxes)?boxes:[];
100
+ const inside=p=>nodeBoxes.some(box=>p.x>box.x&&p.x<box.x+box.w&&p.y>box.y&&p.y<box.y+box.h);
101
+ const blocked=(a,b)=>nodeBoxes.some(box=>throughBox(a,b,box))||
102
+ protectedSegments.some(segment=>crosses(a,b,segment.a,segment.b));
103
+ const crossingCount=route=>{
104
+ let count=0;
105
+ for(let i=1;i<route.length;i++)for(const segment of protectedSegments)
106
+ if(crosses(route[i-1],route[i],segment.a,segment.b))count++;
107
+ return count;
108
+ };
109
+ const before=crossingCount(points);
110
+ if(!before)return{points,detours:0,crossingsAvoided:0};
111
+
112
+ const portals=[];
113
+ for(const segment of protectedSegments){
114
+ const dx=segment.b.x-segment.a.x,dy=segment.b.y-segment.a.y,length=Math.hypot(dx,dy);
115
+ if(length<=epsilon)continue;
116
+ const tx=dx/length,ty=dy/length,nx=-ty,ny=tx;
117
+ for(const endpoint of [segment.a,segment.b])for(const normal of [-1,1])for(const tangent of [-1,1]){
118
+ const p={
119
+ x:endpoint.x+normal*clearance*nx+tangent*clearance*tx,
120
+ y:endpoint.y+normal*clearance*ny+tangent*clearance*ty,
121
+ };
122
+ if(!inside(p))portals.push(p);
123
+ }
124
+ }
125
+
126
+ const solve=(a,b,includeBoxes)=>{
127
+ const vertices=[a,b,...portals];
128
+ if(includeBoxes){
129
+ for(const box of nodeBoxes){
130
+ const l=box.x-2,r=box.x+box.w+2,t=box.y-2,d=box.y+box.h+2;
131
+ for(const p of [{x:l,y:t},{x:l,y:d},{x:r,y:t},{x:r,y:d}])if(!inside(p))vertices.push(p);
132
+ }
133
+ }
134
+ const dist=vertices.map(()=>Infinity),prev=vertices.map(()=>-1),used=new Set();dist[0]=0;
135
+ for(let i=0;i<vertices.length;i++){
136
+ let u=-1;for(let j=0;j<vertices.length;j++)if(!used.has(j)&&(u<0||dist[j]<dist[u]))u=j;
137
+ if(u<0||!Number.isFinite(dist[u]))break;
138
+ if(u===1)break;used.add(u);
139
+ for(let v=0;v<vertices.length;v++){
140
+ if(v===u||used.has(v)||blocked(vertices[u],vertices[v]))continue;
141
+ const next=dist[u]+Math.hypot(vertices[u].x-vertices[v].x,vertices[u].y-vertices[v].y);
142
+ if(next<dist[v]-1e-6){dist[v]=next;prev[v]=u}
143
+ }
144
+ }
145
+ if(!Number.isFinite(dist[1]))return null;
146
+ const found=[];let at=1;
147
+ while(at>0){found.push(vertices[at]);at=prev[at]}
148
+ found.reverse();return found;
149
+ };
150
+
151
+ const out=[points[0]];let detours=0;
152
+ for(let part=1;part<points.length;part++){
153
+ const a=out[out.length-1],b=points[part];
154
+ const directCrosses=protectedSegments.some(segment=>crosses(a,b,segment.a,segment.b));
155
+ if(!directCrosses){out.push(b);continue}
156
+ const found=solve(a,b,false)||solve(a,b,true);
157
+ if(found){out.push(...found);detours++}else out.push(b);
158
+ }
159
+ const after=crossingCount(out);
160
+ if(after>=before)return{points,detours:0,crossingsAvoided:0};
161
+ return{points:out,detours,crossingsAvoided:before-after};
162
+ }
163
+
90
164
  function measure(nodes,edges){
91
165
  const routes=edges.map(e=>{const points=sample(e.d);return{...e,points,left:Math.min(...points.map(p=>p.x)),right:Math.max(...points.map(p=>p.x)),top:Math.min(...points.map(p=>p.y)),bottom:Math.max(...points.map(p=>p.y))}});
92
166
  let crossings=0,overlaps=0,intersections=0;
@@ -113,6 +187,6 @@ const execweaveGeometry=(function(){
113
187
  MAX_EDGE_LENGTH:lengths.at(-1)||0,P95_EDGE_LENGTH:lengths[Math.max(0,Math.ceil(lengths.length*.95)-1)]||0,
114
188
  VISIBLE_NODE_COUNT:nodes.length,VISIBLE_EDGE_COUNT:edges.length};
115
189
  }
116
- return{polyline,sample,crosses,throughBox,measure,avoidNodes};
190
+ return{polyline,sample,crosses,throughBox,measure,avoidNodes,avoidCrossings};
117
191
  })();
118
192
  """.strip()
File without changes
File without changes
File without changes