execweave 0.8.22__tar.gz → 0.8.23__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 (180) hide show
  1. {execweave-0.8.22 → execweave-0.8.23}/PKG-INFO +1 -1
  2. {execweave-0.8.22 → execweave-0.8.23}/pyproject.toml +2 -2
  3. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/__init__.py +1 -1
  4. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/dashboard_shell.py +4 -1
  5. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live.py +13 -1
  6. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_extra_style.py +1 -1
  7. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_readability.py +3 -3
  8. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_style.py +2 -2
  9. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer.py +1 -1
  10. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel.py +11 -0
  11. execweave-0.8.23/src/execweave/viewer_flow_canvas.py +637 -0
  12. execweave-0.8.23/src/execweave/viewer_flow_layout.py +969 -0
  13. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_projection.py +13 -4
  14. {execweave-0.8.22 → execweave-0.8.23}/.gitignore +0 -0
  15. {execweave-0.8.22 → execweave-0.8.23}/LICENSE +0 -0
  16. {execweave-0.8.22 → execweave-0.8.23}/README.md +0 -0
  17. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/__main__.py +0 -0
  18. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/_conversation_records_core.py +0 -0
  19. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/_dashboard_shell_base.py +0 -0
  20. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/_http_proxy_base.py +0 -0
  21. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/_http_proxy_bounded.py +0 -0
  22. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/_http_proxy_stage.py +0 -0
  23. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/agent_bootstrap.py +0 -0
  24. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/agent_topology.py +0 -0
  25. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/agent_trace.py +0 -0
  26. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/agy_preview_sanitize.py +0 -0
  27. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/analysis.py +0 -0
  28. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/anthropic.py +0 -0
  29. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/anthropic_cli.py +0 -0
  30. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/anthropic_full_fidelity.py +0 -0
  31. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_adapter.py +0 -0
  32. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_adapter_base.py +0 -0
  33. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_full_fidelity.py +0 -0
  34. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_full_fidelity_base.py +0 -0
  35. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
  36. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_hook_cli.py +0 -0
  37. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_record.py +0 -0
  38. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_subagent_linkage.py +0 -0
  39. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/antigravity_trace_capability.py +0 -0
  40. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/auto_specialized.py +0 -0
  41. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/backends.py +0 -0
  42. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/benchmark.py +0 -0
  43. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_adapter.py +0 -0
  44. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_child_transcript.py +0 -0
  45. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_delegation.py +0 -0
  46. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_full_fidelity.py +0 -0
  47. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_hook_cli.py +0 -0
  48. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_hook_contract.py +0 -0
  49. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_model_observer.py +0 -0
  50. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/claude_record.py +0 -0
  51. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cli.py +0 -0
  52. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_adapter.py +0 -0
  53. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_conversation.py +0 -0
  54. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_full_fidelity.py +0 -0
  55. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_hook_cli.py +0 -0
  56. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_hook_entry.py +0 -0
  57. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_hook_lifecycle.py +0 -0
  58. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_message_diagnostics.py +0 -0
  59. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_message_transport_diagnostics.py +0 -0
  60. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_record.py +0 -0
  61. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_rollout_structures.py +0 -0
  62. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_rollout_trace.py +0 -0
  63. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/codex_rollout_trace_base.py +0 -0
  64. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/collector.py +0 -0
  65. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/command.py +0 -0
  66. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/content_evidence.py +0 -0
  67. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/content_store.py +0 -0
  68. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_archive.py +0 -0
  69. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_message_identity.py +0 -0
  70. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview.py +0 -0
  71. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_antigravity.py +0 -0
  72. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_claude.py +0 -0
  73. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_codex.py +0 -0
  74. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_common.py +0 -0
  75. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_generic.py +0 -0
  76. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_lines.py +0 -0
  77. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_preview_transcript.py +0 -0
  78. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_records.py +0 -0
  79. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_records_antigravity.py +0 -0
  80. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_records_codex.py +0 -0
  81. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_records_common.py +0 -0
  82. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/conversation_records_ollama.py +0 -0
  83. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/correlation.py +0 -0
  84. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_adapter.py +0 -0
  85. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_delegation.py +0 -0
  86. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_delegation_base.py +0 -0
  87. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_full_fidelity.py +0 -0
  88. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_hook_cli.py +0 -0
  89. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_hook_contract.py +0 -0
  90. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/cursor_record.py +0 -0
  91. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/entry.py +0 -0
  92. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/evidence_availability.py +0 -0
  93. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/evidence_grade.py +0 -0
  94. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/fidelity.py +0 -0
  95. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/filesystem.py +0 -0
  96. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/focus.py +0 -0
  97. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/graph.py +0 -0
  98. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/graph_ops.py +0 -0
  99. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/http_proxy.py +0 -0
  100. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/http_proxy_cli.py +0 -0
  101. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/inference_gateway.py +0 -0
  102. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/inference_gateway_cli.py +0 -0
  103. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/inference_gateway_full_fidelity.py +0 -0
  104. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/inference_identity.py +0 -0
  105. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/inference_identity_cli.py +0 -0
  106. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/integrity.py +0 -0
  107. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/integrity_cli.py +0 -0
  108. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/litellm_callback.py +0 -0
  109. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/litellm_callback_cli.py +0 -0
  110. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_core.py +0 -0
  111. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view.py +0 -0
  112. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_markup.py +0 -0
  113. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_process_layout.py +0 -0
  114. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_script_a.py +0 -0
  115. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_script_b.py +0 -0
  116. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_script_c.py +0 -0
  117. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/live_view_script_d.py +0 -0
  118. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/model_runtime.py +0 -0
  119. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/model_runtime_cli.py +0 -0
  120. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/model_runtime_full_fidelity.py +0 -0
  121. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/openai_compatible.py +0 -0
  122. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/openai_compatible_cli.py +0 -0
  123. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/openai_compatible_full_fidelity.py +0 -0
  124. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_adapter.py +0 -0
  125. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_event_contract.py +0 -0
  126. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_full_fidelity.py +0 -0
  127. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_hook_cli.py +0 -0
  128. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_plugin_cli.py +0 -0
  129. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_record.py +0 -0
  130. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/opencode_task_linkage.py +0 -0
  131. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/overhead_benchmark.py +0 -0
  132. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/provider_capability.py +0 -0
  133. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/provider_lifecycle.py +0 -0
  134. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/provider_record.py +0 -0
  135. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/rule_pack.py +0 -0
  136. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/rule_pack_cli.py +0 -0
  137. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/runtime_endpoint_availability.py +0 -0
  138. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/scalability_benchmark.py +0 -0
  139. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/schema.py +0 -0
  140. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/scope.py +0 -0
  141. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/semantic.py +0 -0
  142. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/sink.py +0 -0
  143. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/strace_backend.py +0 -0
  144. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/stream_assembly.py +0 -0
  145. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/theme.py +0 -0
  146. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/top.py +0 -0
  147. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/top_cli.py +0 -0
  148. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/validate.py +0 -0
  149. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/vendor/dagre.min.js +0 -0
  150. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/view_cli.py +0 -0
  151. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
  152. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_claude.py +0 -0
  153. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_codex.py +0 -0
  154. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_cursor.py +0 -0
  155. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_default.py +0 -0
  156. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_ollama.py +0 -0
  157. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_opencode.py +0 -0
  158. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_agent_panel_registry.py +0 -0
  159. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_content_inspector.py +0 -0
  160. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_dashboard_clean.py +0 -0
  161. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_dashboard_focus.py +0 -0
  162. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_dashboard_hardening.py +0 -0
  163. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
  164. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_dashboard_pr70.py +0 -0
  165. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_edge_decross.py +0 -0
  166. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_execution_flow.py +0 -0
  167. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_execution_flow_provider_normalization.py +0 -0
  168. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_execution_flow_safety.py +0 -0
  169. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_external_endpoints.py +0 -0
  170. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_gif.py +0 -0
  171. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_layout_geometry.py +0 -0
  172. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_layout_v2.py +0 -0
  173. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_layout_v2_detached.py +0 -0
  174. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_limits.py +0 -0
  175. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_live_layout.py +0 -0
  176. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_projection_base.py +0 -0
  177. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_projection_bridges.py +0 -0
  178. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_semantic_projection.py +0 -0
  179. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/viewer_tool_mirror_identity.py +0 -0
  180. {execweave-0.8.22 → execweave-0.8.23}/src/execweave/workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execweave
3
- Version: 0.8.22
3
+ Version: 0.8.23
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.22 release metadata
8
- version = "0.8.22"
7
+ # ExecWeave v0.8.23 release metadata
8
+ version = "0.8.23"
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.22"
3
+ __version__ = "0.8.23"
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from . import _dashboard_shell_base as _base
4
4
  from . import viewer_projection_base as _viewer_projection_base
5
+ from .viewer_flow_canvas import inject_flow_canvas
5
6
  from .viewer_semantic_projection import project_provider_neutral_viewer_graph
6
7
 
7
8
 
@@ -251,7 +252,8 @@ def _stop_conversation_polling_after_finish(html: str) -> str:
251
252
 
252
253
  _viewer_projection_base.project_viewer_graph = project_provider_neutral_viewer_graph
253
254
 
254
- _base.DASHBOARD_HTML = _stop_conversation_polling_after_finish(
255
+ _base.DASHBOARD_HTML = inject_flow_canvas(
256
+ _stop_conversation_polling_after_finish(
255
257
  _surface_provider_neutral_clusters(
256
258
  _defer_camera_takeover_until_node_drag(
257
259
  _preserve_readable_initial_camera(
@@ -263,6 +265,7 @@ _base.DASHBOARD_HTML = _stop_conversation_polling_after_finish(
263
265
  )
264
266
  )
265
267
  )
268
+ )
266
269
  )
267
270
  DASHBOARD_HTML = _base.DASHBOARD_HTML
268
271
  render_static_dashboard_html = _base.render_static_dashboard_html
@@ -10,6 +10,7 @@ from .conversation_records import conversation_index_payload
10
10
  from .dashboard_shell import DASHBOARD_HTML
11
11
  from .graph import logical_event_key
12
12
  from .viewer_limits import resolve_viewer_limits
13
+ from .viewer_flow_layout import layers_of
13
14
  from .viewer_projection import (
14
15
  internal_hook_process_ids_in_event,
15
16
  project_viewer_graph,
@@ -327,7 +328,12 @@ class _LiveState(_BaseLiveState):
327
328
  )
328
329
 
329
330
  def _projected_graph_locked(self) -> dict[str, object]:
330
- projected = project_viewer_graph(self._raw_graph_locked())
331
+ # The columns from the previous tick are a floor, not a cache: new evidence may
332
+ # push a node further right, but a node already on screen never travels back to
333
+ # the left while the operator is reading it.
334
+ previous = getattr(self, "_flow_layers", None)
335
+ projected = project_viewer_graph(self._raw_graph_locked(), previous)
336
+ self._flow_layers = layers_of(projected)
331
337
  if isinstance(projected.get("viewer_projection"), dict):
332
338
  self._viewer_projection_ever_active = True
333
339
  return projected
@@ -410,6 +416,12 @@ class _LiveState(_BaseLiveState):
410
416
  payload.update(counts)
411
417
  if payload.get("kind") == "snapshot":
412
418
  payload["raw_events"] = self._raw_event_snapshot_locked()
419
+ # The canvas description rides along with every update that carries state.
420
+ # A delta names the entities that changed; this names what to draw, so a
421
+ # newly folded node does not appear on screen until the next full snapshot.
422
+ flow = projected.get("viewer_flow")
423
+ if isinstance(flow, dict) and payload.get("kind") in {"snapshot", "delta"}:
424
+ payload["viewer_flow"] = flow
413
425
  return payload
414
426
 
415
427
 
@@ -5,7 +5,7 @@ header{padding-right:92px}#theme-toggle{position:fixed;top:15px;right:16px;z-ind
5
5
  .finished-actions{display:flex;align-items:center;gap:6px}.finished-actions[hidden]{display:none}.finished-actions button,.log-tabs button{height:28px;padding:0 9px;border:1px solid var(--border);border-radius:7px;background:var(--panel2);color:var(--muted);font-size:11px;cursor:pointer}.finished-actions button:hover,.log-tabs button:hover{color:var(--text);border-color:var(--border-strong)}#download-gif{color:var(--latest);border-color:color-mix(in srgb,var(--latest) 40%,var(--border))}#download-gif:disabled{opacity:.55;cursor:progress}
6
6
  .log-tabs{display:flex;gap:4px;margin-left:auto}.log-tabs button.active{background:var(--panel);color:var(--text);box-shadow:inset 0 0 0 1px var(--border-strong)}.filter-group{margin-left:0}
7
7
  #raw-log{overflow:auto;min-height:0}#raw-log[hidden]{display:none}.raw-head,.raw-row{display:grid;grid-template-columns:64px 92px 190px 170px minmax(300px,1fr);align-items:center;gap:10px;padding:0 12px}.raw-head{height:28px;position:sticky;top:0;z-index:2;background:var(--panel);border-bottom:1px solid var(--border);color:var(--muted);font-size:9px;text-transform:uppercase;letter-spacing:.08em}.raw-row{min-height:38px;border-bottom:1px solid color-mix(in srgb,var(--border) 72%,transparent);font:11px/1.35 ui-monospace,SFMono-Regular,Menlo,monospace;cursor:pointer}.raw-row:hover{background:var(--panel2)}.raw-row.selected{background:color-mix(in srgb,var(--selected) 10%,var(--panel));box-shadow:inset 2px 0 0 var(--selected)}.raw-line,.raw-time{color:var(--muted);font-variant-numeric:tabular-nums}.raw-event{color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.raw-relation{font-weight:700}.raw-json{color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
8
- .replay-hidden{opacity:0!important;pointer-events:none}.replay-active rect{stroke:var(--latest)!important;stroke-width:3!important}.edge.replay-active{stroke:var(--latest)!important;stroke-width:2.4!important;opacity:1!important}
8
+ .replay-hidden{opacity:0!important;pointer-events:none}.replay-active rect{stroke:var(--latest)!important;stroke-width:3!important}.edge.replay-active{stroke:var(--latest)!important;stroke-width:4.8!important;opacity:1!important}
9
9
  @media(max-width:1100px){.finished-actions #open-final{display:none}.raw-head,.raw-row{grid-template-columns:54px 82px 150px 130px minmax(260px,1fr)}}
10
10
  @media(max-width:760px){header{padding-right:92px}.finished-actions{order:4;margin-left:auto}.log-tabs{margin-left:auto}.filter-group{display:none}.raw-head,.raw-row{grid-template-columns:48px 78px minmax(220px,1fr)}.raw-head>*:nth-child(4),.raw-head>*:nth-child(5),.raw-row>*:nth-child(4),.raw-row>*:nth-child(5){display:none}}
11
11
  """
@@ -7,10 +7,10 @@ LIVE_READABILITY_STYLE = r"""
7
7
  #svg.execweave-crowded .label.context-visible,
8
8
  #svg.execweave-crowded .label.selected{opacity:1}
9
9
  .edge.context-dim{opacity:.055!important}
10
- .edge.context-related:not(.dim){opacity:1;stroke-width:2.2}
11
- .edge.edge-hover:not(.dim){opacity:1;stroke-width:2.2}
10
+ .edge.context-related:not(.dim){opacity:1;stroke-width:4.4}
11
+ .edge.edge-hover:not(.dim){opacity:1;stroke-width:4.4}
12
12
  .edge.bundle-member:not(.context-dim){opacity:.52}
13
- .edge.bundle-representative:not(.context-dim){opacity:.94;stroke-width:1.8}
13
+ .edge.bundle-representative:not(.context-dim){opacity:.94;stroke-width:3.6}
14
14
  .node.context-dim{opacity:.32}
15
15
  .label.context-dim{opacity:0!important}
16
16
  .label.context-visible{fill:var(--text)}
@@ -23,8 +23,8 @@ header{grid-column:1/3;display:flex;align-items:center;gap:12px;padding:0 16px;b
23
23
  #protective{position:absolute;inset:18px;z-index:4;display:grid;place-items:center;padding:24px;text-align:center;border:1px solid var(--border);border-radius:14px;background:color-mix(in srgb,var(--panel) 96%,transparent);box-shadow:var(--shadow)}#protective[hidden]{display:none}#protective strong{display:block;margin-bottom:8px;font-size:18px}#protective p{max-width:680px;margin:6px auto;color:var(--muted)}
24
24
  .node{cursor:pointer}.node rect{stroke:var(--border-strong);stroke-width:1.25;rx:10;ry:10;transition:stroke .18s ease,stroke-width .18s ease,opacity .18s ease,filter .18s ease}.node:hover rect{stroke:color-mix(in srgb,var(--text) 45%,var(--border-strong));stroke-width:1.8}.node text{fill:#f8fafc;pointer-events:none;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;text-rendering:geometricPrecision;-webkit-font-smoothing:antialiased}.node .type{fill:color-mix(in srgb,var(--text) 72%,var(--muted));font-size:9.5px;font-weight:650;text-transform:uppercase;letter-spacing:.08em}.node .name-label{fill:#f8fafc;font-size:13px;font-weight:650;letter-spacing:-.01em}.node .name-label tspan{font-size:12.5px;font-weight:600;fill:#f8fafc}.node .detail-text,.node .secondary-text{font-size:10px;fill:var(--muted);font-weight:500;letter-spacing:.01em}.node.dim{opacity:.1}.node.context-dim{opacity:.32;transition:opacity .2s ease}.node.context-neighbor rect{stroke:color-mix(in srgb,var(--selected) 72%,var(--border-strong));stroke-width:2.0;filter:drop-shadow(0 0 5px color-mix(in srgb,var(--selected) 40%,transparent))}.node.selected rect{stroke:var(--selected);stroke-width:2.8;filter:drop-shadow(0 0 8px color-mix(in srgb,var(--selected) 65%,transparent))}.node.latest rect{stroke:var(--latest);stroke-width:2.2;animation:latestNode 2.4s cubic-bezier(0.16,1,0.3,1) forwards}
25
25
  @keyframes latestNode{0%{stroke-width:4.6;stroke-opacity:1;filter:drop-shadow(0 0 10px var(--latest))}28%{stroke-width:3.4;stroke-opacity:.92;filter:drop-shadow(0 0 7px var(--latest))}60%{stroke-width:2.6;stroke-opacity:.82;filter:drop-shadow(0 0 4px color-mix(in srgb,var(--latest) 50%,transparent))}100%{stroke-width:2.0;stroke-opacity:.72;filter:none}}
26
- .edge{fill:none;stroke:var(--edge);stroke-width:1.2;opacity:.52;marker-end:url(#arrow);transition:stroke .18s ease,stroke-width .18s ease,opacity .18s ease}.edge.causal{stroke:var(--causal);opacity:.68}.edge.noncausal{stroke:var(--noncausal);stroke-dasharray:6 5;opacity:.65}.edge.inferred{stroke:var(--inferred);stroke-dasharray:4 5;opacity:.65}.edge.dim{opacity:.05}.edge.context-dim{opacity:.055!important}.edge.context-related{stroke-width:1.8;opacity:.95}.edge.edge-hover{stroke:var(--selected);stroke-width:2;opacity:1}.edge.selected{stroke:var(--selected);stroke-width:2.6;opacity:1;filter:drop-shadow(0 0 5px color-mix(in srgb,var(--selected) 55%,transparent))}.edge.latest-edge{stroke:var(--latest);stroke-width:2;stroke-dasharray:8 5;opacity:1;animation:latestEdge 2.4s ease-out forwards}.edge-hit{fill:none;stroke:transparent;stroke-width:12;cursor:pointer}.label{fill:var(--muted);font-size:10px;font-weight:600;letter-spacing:.02em;pointer-events:none;paint-order:stroke fill;stroke:var(--bg);stroke-width:3.5px;stroke-linejoin:round;transition:fill .15s ease,opacity .15s ease}.label.selected{fill:var(--selected);font-weight:700;stroke:var(--panel)}.label.context-visible{fill:var(--text);font-weight:650;opacity:.95}.label.edge-hover{fill:var(--text);font-weight:700}.label.context-dim{opacity:0!important}
27
- @keyframes latestEdge{0%{stroke-dashoffset:0;stroke-width:2.6;opacity:1}45%{stroke-dashoffset:-18;stroke-width:2.2;opacity:.92}100%{stroke-dashoffset:-36;stroke-width:1.8;opacity:.82}}
26
+ .edge{fill:none;stroke:var(--edge);stroke-width:2.4;opacity:.52;marker-end:url(#arrow);transition:stroke .18s ease,stroke-width .18s ease,opacity .18s ease}.edge.causal{stroke:var(--causal);opacity:.68}.edge.noncausal{stroke:var(--noncausal);stroke-dasharray:6 5;opacity:.65}.edge.inferred{stroke:var(--inferred);stroke-dasharray:4 5;opacity:.65}.edge.dim{opacity:.05}.edge.context-dim{opacity:.055!important}.edge.context-related{stroke-width:3.6;opacity:.95}.edge.edge-hover{stroke:var(--selected);stroke-width:4;opacity:1}.edge.selected{stroke:var(--selected);stroke-width:5.2;opacity:1;filter:drop-shadow(0 0 5px color-mix(in srgb,var(--selected) 55%,transparent))}.edge.latest-edge{stroke:var(--latest);stroke-width:4;stroke-dasharray:8 5;opacity:1;animation:latestEdge 2.4s ease-out forwards}.edge-hit{fill:none;stroke:transparent;stroke-width:12;cursor:pointer}.label{fill:var(--muted);font-size:10px;font-weight:600;letter-spacing:.02em;pointer-events:none;paint-order:stroke fill;stroke:var(--bg);stroke-width:3.5px;stroke-linejoin:round;transition:fill .15s ease,opacity .15s ease}.label.selected{fill:var(--selected);font-weight:700;stroke:var(--panel)}.label.context-visible{fill:var(--text);font-weight:650;opacity:.95}.label.edge-hover{fill:var(--text);font-weight:700}.label.context-dim{opacity:0!important}
27
+ @keyframes latestEdge{0%{stroke-dashoffset:0;stroke-width:5.2;opacity:1}45%{stroke-dashoffset:-18;stroke-width:4.4;opacity:.92}100%{stroke-dashoffset:-36;stroke-width:3.6;opacity:.82}}
28
28
  #inspector{grid-column:2;grid-row:2;min-width:0;min-height:0;overflow:auto;background:var(--panel);padding:14px}.inspector-section+.inspector-section{margin-top:18px;padding-top:16px;border-top:1px solid var(--border)}.eyebrow{font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-weight:750}.current-title{font-size:16px;font-weight:750;margin-top:6px;overflow-wrap:anywhere}.current-sub{color:var(--muted);font-size:12px;margin-top:4px;overflow-wrap:anywhere}.kv{display:grid;grid-template-columns:92px minmax(0,1fr);gap:7px 10px;margin-top:12px;font-size:12px}.kv dt{color:var(--muted)}.kv dd{margin:0;overflow-wrap:anywhere}.badge{display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:999px;padding:2px 7px;background:var(--panel2);font-size:10px;color:var(--muted)}.badge.direct{color:var(--causal);border-color:color-mix(in srgb,var(--causal) 45%,var(--border))}.badge.inferred{color:var(--inferred);border-color:color-mix(in srgb,var(--inferred) 45%,var(--border))}
29
29
  #details-empty{color:var(--muted);font-size:12px;margin-top:8px}.raw-toggle{margin-top:12px}.raw-toggle summary{cursor:pointer;color:var(--muted);font-size:11px}.raw-toggle pre{white-space:pre-wrap;overflow-wrap:anywhere;font:11px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--panel3);border:1px solid var(--border);border-radius:9px;padding:10px;margin:8px 0 0}.raw-target-actions{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}.raw-target-actions button{padding:4px 8px;font-size:11px}
30
30
  #activity-panel{grid-column:1/3;grid-row:3;min-width:0;min-height:0;display:grid;grid-template-rows:44px minmax(0,1fr);background:var(--panel);border-top:1px solid var(--border)}.activity-toolbar{display:flex;align-items:center;gap:10px;padding:0 12px;border-bottom:1px solid var(--border)}.activity-toolbar .count{color:var(--muted);font-size:11px}.filter-group{display:flex;gap:5px;margin-left:auto}.filter-group button{height:27px;padding:0 9px;border:1px solid transparent;border-radius:7px;background:transparent;color:var(--muted);font-size:11px;cursor:pointer}.filter-group button.active{border-color:var(--border);background:var(--panel2);color:var(--text)}
@@ -120,7 +120,7 @@ aside{overflow:auto;border-left:1px solid var(--border);background:var(--panel);
120
120
  button{border:1px solid var(--border);background:var(--panel);color:var(--text);border-radius:7px;padding:6px 9px;cursor:pointer}button:hover{border-color:var(--selected)}button:disabled{opacity:.45;cursor:default}
121
121
  .controls{position:absolute;top:12px;left:12px;z-index:5;display:flex;gap:6px;flex-wrap:wrap}
122
122
  .node rect{stroke:var(--border);stroke-width:1.2;rx:9;ry:9}.node text{pointer-events:none;fill:var(--text)}.node .node-type{fill:var(--muted);font-size:10px}.node.selected rect{stroke:var(--selected);stroke-width:2.5}.node.dim{opacity:.13}.node.cluster rect{stroke:var(--selected);stroke-dasharray:6 4}
123
- .edge{fill:none;stroke:var(--edge);stroke-width:1.4;opacity:.75;cursor:pointer}.edge.causal{stroke:var(--causal)}.edge.noncausal{stroke:var(--noncausal);stroke-dasharray:6 5}.edge.inferred{stroke:var(--inferred);stroke-width:1.8;stroke-dasharray:2 5}.edge.identity{stroke:var(--identity);stroke-width:2.2;stroke-dasharray:none}.edge.dim{opacity:.06}.edge-hit{fill:none;stroke:transparent;stroke-width:12;cursor:pointer}.edge-label{fill:var(--muted);font-size:9px;pointer-events:none}.edge-label.dim{opacity:.08}
123
+ .edge{fill:none;stroke:var(--edge);stroke-width:2.8;opacity:.75;cursor:pointer}.edge.causal{stroke:var(--causal)}.edge.noncausal{stroke:var(--noncausal);stroke-dasharray:6 5}.edge.inferred{stroke:var(--inferred);stroke-width:3.6;stroke-dasharray:2 5}.edge.identity{stroke:var(--identity);stroke-width:4.4;stroke-dasharray:none}.edge.dim{opacity:.06}.edge-hit{fill:none;stroke:transparent;stroke-width:12;cursor:pointer}.edge-label{fill:var(--muted);font-size:9px;pointer-events:none}.edge-label.dim{opacity:.08}
124
124
  .legend{display:flex;flex-wrap:wrap;gap:8px 12px}.legend span{display:inline-flex;align-items:center;gap:5px;color:var(--muted);font-size:12px}.dot{width:9px;height:9px;border-radius:50%;display:inline-block}
125
125
  @media(max-width:900px){#app{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr) 220px}header{grid-column:1}aside{border-left:0;border-top:1px solid var(--border)}#search{width:160px}}
126
126
  </style>
@@ -324,7 +324,18 @@ function occurrenceList(a){
324
324
  .map(item=>`${moment(item?.first_seen)}${item?.pid?` pid ${item.pid}`:''}`)
325
325
  .join('\n');
326
326
  }
327
+ // A node the flow layout drew in place of others is still a real node with a panel of
328
+ // its own, so it keeps every card it would have had and says what it absorbed at the
329
+ // end. A node whose only purpose is to stand for others is the separate `viewer_folded`
330
+ // case below, and that one is a list of what it holds and nothing else.
327
331
  function nodeCards(node){
332
+ const a=attrs(node),rows=execweaveNodeCardsBase(node);
333
+ if(!a.viewer_absorbed||a.viewer_folded)return rows;
334
+ const held=foldedList(a);
335
+ if(held)rows.push(['Also holding',held]);
336
+ return rows;
337
+ }
338
+ function execweaveNodeCardsBase(node){
328
339
  const a=attrs(node),kind=String(node?.type||'');
329
340
  const rows=[];
330
341
  const add=(label,value)=>{const text=commandText(value);if(text)rows.push([label,text])};