execweave 0.8.23__tar.gz → 0.8.24__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 (187) hide show
  1. {execweave-0.8.23 → execweave-0.8.24}/PKG-INFO +22 -1
  2. {execweave-0.8.23 → execweave-0.8.24}/README.md +21 -0
  3. {execweave-0.8.23 → execweave-0.8.24}/pyproject.toml +7 -2
  4. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/__init__.py +1 -1
  5. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/_conversation_records_core.py +4 -2
  6. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/collector.py +28 -0
  7. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/content_store.py +43 -19
  8. execweave-0.8.24/src/execweave/cursor_lifecycle.py +159 -0
  9. execweave-0.8.24/src/execweave/framework_adapters/__init__.py +34 -0
  10. execweave-0.8.24/src/execweave/framework_adapters/autogen.py +345 -0
  11. execweave-0.8.24/src/execweave/framework_adapters/base.py +464 -0
  12. execweave-0.8.24/src/execweave/framework_adapters/camel.py +190 -0
  13. execweave-0.8.24/src/execweave/framework_adapters/metagpt.py +237 -0
  14. execweave-0.8.24/src/execweave/framework_adapters/registry.py +90 -0
  15. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live.py +4 -2
  16. {execweave-0.8.23 → execweave-0.8.24}/.gitignore +0 -0
  17. {execweave-0.8.23 → execweave-0.8.24}/LICENSE +0 -0
  18. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/__main__.py +0 -0
  19. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/_dashboard_shell_base.py +0 -0
  20. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/_http_proxy_base.py +0 -0
  21. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/_http_proxy_bounded.py +0 -0
  22. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/_http_proxy_stage.py +0 -0
  23. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/agent_bootstrap.py +0 -0
  24. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/agent_topology.py +0 -0
  25. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/agent_trace.py +0 -0
  26. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/agy_preview_sanitize.py +0 -0
  27. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/analysis.py +0 -0
  28. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/anthropic.py +0 -0
  29. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/anthropic_cli.py +0 -0
  30. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/anthropic_full_fidelity.py +0 -0
  31. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_adapter.py +0 -0
  32. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_adapter_base.py +0 -0
  33. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_full_fidelity.py +0 -0
  34. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_full_fidelity_base.py +0 -0
  35. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
  36. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_hook_cli.py +0 -0
  37. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_record.py +0 -0
  38. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_subagent_linkage.py +0 -0
  39. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/antigravity_trace_capability.py +0 -0
  40. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/auto_specialized.py +0 -0
  41. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/backends.py +0 -0
  42. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/benchmark.py +0 -0
  43. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_adapter.py +0 -0
  44. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_child_transcript.py +0 -0
  45. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_delegation.py +0 -0
  46. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_full_fidelity.py +0 -0
  47. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_hook_cli.py +0 -0
  48. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_hook_contract.py +0 -0
  49. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_model_observer.py +0 -0
  50. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/claude_record.py +0 -0
  51. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cli.py +0 -0
  52. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_adapter.py +0 -0
  53. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_conversation.py +0 -0
  54. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_full_fidelity.py +0 -0
  55. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_hook_cli.py +0 -0
  56. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_hook_entry.py +0 -0
  57. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_hook_lifecycle.py +0 -0
  58. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_message_diagnostics.py +0 -0
  59. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_message_transport_diagnostics.py +0 -0
  60. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_record.py +0 -0
  61. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_rollout_structures.py +0 -0
  62. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_rollout_trace.py +0 -0
  63. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/codex_rollout_trace_base.py +0 -0
  64. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/command.py +0 -0
  65. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/content_evidence.py +0 -0
  66. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_archive.py +0 -0
  67. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_message_identity.py +0 -0
  68. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview.py +0 -0
  69. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_antigravity.py +0 -0
  70. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_claude.py +0 -0
  71. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_codex.py +0 -0
  72. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_common.py +0 -0
  73. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_generic.py +0 -0
  74. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_lines.py +0 -0
  75. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_preview_transcript.py +0 -0
  76. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_records.py +0 -0
  77. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_records_antigravity.py +0 -0
  78. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_records_codex.py +0 -0
  79. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_records_common.py +0 -0
  80. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/conversation_records_ollama.py +0 -0
  81. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/correlation.py +0 -0
  82. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_adapter.py +0 -0
  83. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_delegation.py +0 -0
  84. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_delegation_base.py +0 -0
  85. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_full_fidelity.py +0 -0
  86. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_hook_cli.py +0 -0
  87. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_hook_contract.py +0 -0
  88. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/cursor_record.py +0 -0
  89. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/dashboard_shell.py +0 -0
  90. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/entry.py +0 -0
  91. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/evidence_availability.py +0 -0
  92. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/evidence_grade.py +0 -0
  93. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/fidelity.py +0 -0
  94. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/filesystem.py +0 -0
  95. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/focus.py +0 -0
  96. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/graph.py +0 -0
  97. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/graph_ops.py +0 -0
  98. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/http_proxy.py +0 -0
  99. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/http_proxy_cli.py +0 -0
  100. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/inference_gateway.py +0 -0
  101. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/inference_gateway_cli.py +0 -0
  102. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/inference_gateway_full_fidelity.py +0 -0
  103. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/inference_identity.py +0 -0
  104. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/inference_identity_cli.py +0 -0
  105. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/integrity.py +0 -0
  106. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/integrity_cli.py +0 -0
  107. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/litellm_callback.py +0 -0
  108. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/litellm_callback_cli.py +0 -0
  109. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_core.py +0 -0
  110. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view.py +0 -0
  111. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_extra_style.py +0 -0
  112. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_markup.py +0 -0
  113. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_process_layout.py +0 -0
  114. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_readability.py +0 -0
  115. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_script_a.py +0 -0
  116. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_script_b.py +0 -0
  117. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_script_c.py +0 -0
  118. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_script_d.py +0 -0
  119. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/live_view_style.py +0 -0
  120. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/model_runtime.py +0 -0
  121. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/model_runtime_cli.py +0 -0
  122. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/model_runtime_full_fidelity.py +0 -0
  123. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/openai_compatible.py +0 -0
  124. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/openai_compatible_cli.py +0 -0
  125. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/openai_compatible_full_fidelity.py +0 -0
  126. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_adapter.py +0 -0
  127. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_event_contract.py +0 -0
  128. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_full_fidelity.py +0 -0
  129. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_hook_cli.py +0 -0
  130. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_plugin_cli.py +0 -0
  131. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_record.py +0 -0
  132. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/opencode_task_linkage.py +0 -0
  133. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/overhead_benchmark.py +0 -0
  134. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/provider_capability.py +0 -0
  135. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/provider_lifecycle.py +0 -0
  136. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/provider_record.py +0 -0
  137. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/rule_pack.py +0 -0
  138. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/rule_pack_cli.py +0 -0
  139. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/runtime_endpoint_availability.py +0 -0
  140. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/scalability_benchmark.py +0 -0
  141. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/schema.py +0 -0
  142. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/scope.py +0 -0
  143. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/semantic.py +0 -0
  144. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/sink.py +0 -0
  145. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/strace_backend.py +0 -0
  146. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/stream_assembly.py +0 -0
  147. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/theme.py +0 -0
  148. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/top.py +0 -0
  149. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/top_cli.py +0 -0
  150. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/validate.py +0 -0
  151. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/vendor/dagre.min.js +0 -0
  152. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/view_cli.py +0 -0
  153. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer.py +0 -0
  154. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel.py +0 -0
  155. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
  156. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_claude.py +0 -0
  157. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_codex.py +0 -0
  158. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_cursor.py +0 -0
  159. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_default.py +0 -0
  160. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_ollama.py +0 -0
  161. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_opencode.py +0 -0
  162. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_agent_panel_registry.py +0 -0
  163. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_content_inspector.py +0 -0
  164. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_dashboard_clean.py +0 -0
  165. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_dashboard_focus.py +0 -0
  166. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_dashboard_hardening.py +0 -0
  167. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
  168. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_dashboard_pr70.py +0 -0
  169. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_edge_decross.py +0 -0
  170. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_execution_flow.py +0 -0
  171. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_execution_flow_provider_normalization.py +0 -0
  172. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_execution_flow_safety.py +0 -0
  173. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_external_endpoints.py +0 -0
  174. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_flow_canvas.py +0 -0
  175. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_flow_layout.py +0 -0
  176. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_gif.py +0 -0
  177. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_layout_geometry.py +0 -0
  178. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_layout_v2.py +0 -0
  179. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_layout_v2_detached.py +0 -0
  180. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_limits.py +0 -0
  181. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_live_layout.py +0 -0
  182. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_projection.py +0 -0
  183. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_projection_base.py +0 -0
  184. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_projection_bridges.py +0 -0
  185. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_semantic_projection.py +0 -0
  186. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/viewer_tool_mirror_identity.py +0 -0
  187. {execweave-0.8.23 → execweave-0.8.24}/src/execweave/workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execweave
3
- Version: 0.8.23
3
+ Version: 0.8.24
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
@@ -369,3 +369,24 @@ Issues and pull requests are welcome. Keep new integrations evidence-aware: docu
369
369
  ## License
370
370
 
371
371
  ExecWeave is distributed under the **PolyForm Noncommercial License 1.0.0**. See [LICENSE](LICENSE) for the full terms.
372
+ ## Framework Adapter SDK
373
+
374
+ ExecWeave includes an optional authoritative adapter SDK for CAMEL Workforce,
375
+ AutoGen AgentChat/Core, and MetaGPT. Adapters emit canonical agent, task,
376
+ message, model, and tool records; they do not infer logical conversations from
377
+ process names or network traffic. Content capture is opt-in and hidden
378
+ reasoning/private reasoning is never captured by the SDK. Transport credentials
379
+ are removed from semantic metadata.
380
+
381
+ See [the framework adapter guide](docs/framework-adapters.md) for the public
382
+ API, compatibility matrix, live/final parity contract, and official CAMEL,
383
+ AutoGen, and MetaGPT paper references. Current framework versions still require
384
+ the corresponding optional dependency and an authoritative callback or event
385
+ boundary in the application.
386
+
387
+ Paper context: Li et al., *CAMEL: Communicative Agents for "Mind" Exploration of Large Language Model Society* ([arXiv:2303.17760](https://arxiv.org/abs/2303.17760), 2023); Wu et al., *AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation* ([arXiv:2308.08155](https://arxiv.org/abs/2308.08155), 2023); Hong et al., *MetaGPT: Meta Programming for a Multi-Agent Collaborative Framework* ([OpenReview, ICLR 2024](https://openreview.net/forum?id=VtmBAGCN7o)).
388
+
389
+ ```python
390
+ from execweave.framework_adapters import AdapterContext, CAMELAdapter
391
+ adapter = CAMELAdapter(AdapterContext.from_environment("camel"))
392
+ ```
@@ -309,3 +309,24 @@ Issues and pull requests are welcome. Keep new integrations evidence-aware: docu
309
309
  ## License
310
310
 
311
311
  ExecWeave is distributed under the **PolyForm Noncommercial License 1.0.0**. See [LICENSE](LICENSE) for the full terms.
312
+ ## Framework Adapter SDK
313
+
314
+ ExecWeave includes an optional authoritative adapter SDK for CAMEL Workforce,
315
+ AutoGen AgentChat/Core, and MetaGPT. Adapters emit canonical agent, task,
316
+ message, model, and tool records; they do not infer logical conversations from
317
+ process names or network traffic. Content capture is opt-in and hidden
318
+ reasoning/private reasoning is never captured by the SDK. Transport credentials
319
+ are removed from semantic metadata.
320
+
321
+ See [the framework adapter guide](docs/framework-adapters.md) for the public
322
+ API, compatibility matrix, live/final parity contract, and official CAMEL,
323
+ AutoGen, and MetaGPT paper references. Current framework versions still require
324
+ the corresponding optional dependency and an authoritative callback or event
325
+ boundary in the application.
326
+
327
+ Paper context: Li et al., *CAMEL: Communicative Agents for "Mind" Exploration of Large Language Model Society* ([arXiv:2303.17760](https://arxiv.org/abs/2303.17760), 2023); Wu et al., *AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation* ([arXiv:2308.08155](https://arxiv.org/abs/2308.08155), 2023); Hong et al., *MetaGPT: Meta Programming for a Multi-Agent Collaborative Framework* ([OpenReview, ICLR 2024](https://openreview.net/forum?id=VtmBAGCN7o)).
328
+
329
+ ```python
330
+ from execweave.framework_adapters import AdapterContext, CAMELAdapter
331
+ adapter = CAMELAdapter(AdapterContext.from_environment("camel"))
332
+ ```
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "execweave"
7
- # ExecWeave v0.8.23 release metadata
8
- version = "0.8.23"
7
+ # ExecWeave v0.8.24 release metadata
8
+ version = "0.8.24"
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"
@@ -69,6 +69,11 @@ Repository = "https://github.com/Irish-kw/ExecWeave"
69
69
  Documentation = "https://github.com/Irish-kw/ExecWeave#documentation"
70
70
  Issues = "https://github.com/Irish-kw/ExecWeave/issues"
71
71
 
72
+ [project.entry-points."execweave.framework_adapters"]
73
+ camel = "execweave.framework_adapters.camel:CAMELAdapter"
74
+ autogen = "execweave.framework_adapters.autogen:AutoGenAdapter"
75
+ metagpt = "execweave.framework_adapters.metagpt:MetaGPTAdapter"
76
+
72
77
  [project.scripts]
73
78
  execweave = "execweave.entry:main"
74
79
  execweave-top = "execweave.top_cli:main"
@@ -1,3 +1,3 @@
1
1
  """ExecWeave runtime graph package."""
2
2
 
3
- __version__ = "0.8.23"
3
+ __version__ = "0.8.24"
@@ -4,6 +4,7 @@ import json
4
4
  import re
5
5
  from pathlib import Path
6
6
  from typing import Any
7
+ from .content_store import _filesystem_path
7
8
 
8
9
  from .agent_topology import (
9
10
  COMPLETENESS_ROUTING_ONLY,
@@ -108,8 +109,9 @@ def _provider(source: dict[str, Any] | None, content_kind: str) -> str:
108
109
 
109
110
  def _run_local_path(root: Path, relative: str) -> Path | None:
110
111
  try:
111
- candidate = (root / relative).resolve(strict=False)
112
- candidate.relative_to(root)
112
+ root_fs = _filesystem_path(root)
113
+ candidate = (root_fs / relative).resolve(strict=False)
114
+ candidate.relative_to(root_fs)
113
115
  except (OSError, RuntimeError, ValueError):
114
116
  return None
115
117
  return candidate if candidate.is_file() else None
@@ -20,6 +20,11 @@ from .auto_specialized import (
20
20
  run_post_command_specialized_probe,
21
21
  )
22
22
  from .command import resolve_launch_command
23
+ from .cursor_lifecycle import (
24
+ is_cursor_invocation,
25
+ process_baseline,
26
+ run_cursor_handoff,
27
+ )
23
28
  from .filesystem import FileWatcher
24
29
  from .schema import Entity, RuntimeEvent
25
30
  from .sink import JsonlSink
@@ -137,6 +142,8 @@ class RuntimeCollector:
137
142
  self._network_sample_errors = 0
138
143
  self._network_access_denied = 0
139
144
  self._collector_children_baseline: dict[int, float] | None = None
145
+ self._preserved_processes: set[tuple[int, float]] = set()
146
+ self._cursor_handoff_info: dict[str, object] = {}
140
147
 
141
148
  def _filesystem_excluded_roots(self) -> list[Path]:
142
149
  """Return ExecWeave-owned paths that must never become workload evidence.
@@ -165,6 +172,12 @@ class RuntimeCollector:
165
172
  raise ValueError("command must not be empty")
166
173
 
167
174
  launch_command = resolve_launch_command(command)
175
+ cursor_invocation = os.name == "nt" and is_cursor_invocation(command)
176
+ cursor_baseline = process_baseline(launch_command[0]) if cursor_invocation else set()
177
+ self._preserved_processes = set()
178
+ self._cursor_handoff_info = {
179
+ "cursor_lifecycle_handoff": "launcher" if cursor_invocation else "not_applicable",
180
+ }
168
181
  agent_name = infer_agent_name(command)
169
182
  agent = Entity(type="agent", id=f"agent:{agent_name}", name=agent_name)
170
183
  session = Entity(
@@ -206,6 +219,7 @@ class RuntimeCollector:
206
219
  process: subprocess.Popen[bytes] | None = None
207
220
  owned: list[psutil.Process] = []
208
221
  return_code = 1
222
+ cursor_root_snapshot: ProcessSnapshot | None = None
209
223
  interrupted = False
210
224
  collector_error_type: str | None = None
211
225
  workload_terminated_due_to_collector_error = False
@@ -236,6 +250,7 @@ class RuntimeCollector:
236
250
  snapshot = _safe_process_snapshot(root)
237
251
  if snapshot is not None:
238
252
  self._record_process_start(snapshot, parent=session, relation="LAUNCHED")
253
+ cursor_root_snapshot = snapshot if cursor_invocation else None
239
254
 
240
255
  with auto_specialized_probe(command, admission=live_probe_admission):
241
256
  while process.poll() is None:
@@ -245,6 +260,14 @@ class RuntimeCollector:
245
260
  self._sample_process_tree(root)
246
261
  self._mark_disappeared_processes(set())
247
262
  return_code = int(process.returncode or 0)
263
+
264
+ if cursor_invocation and cursor_root_snapshot is not None:
265
+ run_cursor_handoff(
266
+ self,
267
+ root_snapshot=cursor_root_snapshot,
268
+ executable=launch_command[0],
269
+ baseline=cursor_baseline,
270
+ )
248
271
  except KeyboardInterrupt:
249
272
  interrupted = True
250
273
  return_code = 130
@@ -300,6 +323,7 @@ class RuntimeCollector:
300
323
  "network_sample_errors": self._network_sample_errors,
301
324
  "network_access_denied": self._network_access_denied,
302
325
  "execweave_version": __version__,
326
+ **self._cursor_handoff_info,
303
327
  },
304
328
  )
305
329
  )
@@ -394,6 +418,8 @@ class RuntimeCollector:
394
418
  def add_with_descendants(candidate: psutil.Process) -> None:
395
419
  if not self._process_is_live(candidate):
396
420
  return
421
+ if (candidate.pid, candidate.create_time()) in self._preserved_processes:
422
+ return
397
423
  owned[candidate.pid] = candidate
398
424
  try:
399
425
  descendants = candidate.children(recursive=True)
@@ -401,6 +427,8 @@ class RuntimeCollector:
401
427
  descendants = []
402
428
  for child in descendants:
403
429
  if self._process_is_live(child):
430
+ if (child.pid, child.create_time()) in self._preserved_processes:
431
+ continue
404
432
  owned[child.pid] = child
405
433
 
406
434
  if process.poll() is None:
@@ -13,6 +13,20 @@ _HASH_ALGORITHM = "sha256"
13
13
  _COPY_CHUNK_BYTES = 1024 * 1024
14
14
 
15
15
 
16
+ def _filesystem_path(path: Path) -> Path:
17
+ """Use Win32 extended paths for content stores beyond ``MAX_PATH``."""
18
+ if os.name != "nt":
19
+ return path
20
+ value = os.fspath(path)
21
+ if value.startswith("\\\\?\\"):
22
+ return path
23
+ if value.startswith("\\\\"):
24
+ return Path("\\\\?\\UNC\\" + value[2:])
25
+ if os.path.isabs(value):
26
+ return Path("\\\\?\\" + value)
27
+ return path
28
+
29
+
16
30
  @dataclass(frozen=True)
17
31
  class ContentReference:
18
32
  """Reference to one complete locally stored observation.
@@ -118,9 +132,12 @@ class FullFidelityContentStore:
118
132
  if not content_kind:
119
133
  raise ValueError("content_kind must not be empty")
120
134
  source_path = Path(source).expanduser().resolve()
121
- if not source_path.is_file():
135
+ source_fs = _filesystem_path(source_path)
136
+ if not source_fs.is_file():
122
137
  raise FileNotFoundError(source_path)
123
- destination_dir = self.run_root / _CONTENT_DIR / _HASH_ALGORITHM
138
+ destination_dir = _filesystem_path(
139
+ self.run_root / _CONTENT_DIR / _HASH_ALGORITHM
140
+ )
124
141
  destination_dir.mkdir(parents=True, exist_ok=True)
125
142
  if os.name != "nt":
126
143
  try:
@@ -128,9 +145,9 @@ class FullFidelityContentStore:
128
145
  except OSError:
129
146
  pass
130
147
 
131
- before = source_path.stat()
148
+ before = source_fs.stat()
132
149
  fd, temp_name = tempfile.mkstemp(prefix=".execweave-content-", dir=destination_dir)
133
- temp_path = Path(temp_name)
150
+ temp_path = _filesystem_path(Path(temp_name))
134
151
  digest = hashlib.sha256()
135
152
  size = 0
136
153
  try:
@@ -139,7 +156,7 @@ class FullFidelityContentStore:
139
156
  os.fchmod(fd, 0o600)
140
157
  except OSError:
141
158
  pass
142
- with source_path.open("rb") as source_handle, os.fdopen(
159
+ with source_fs.open("rb") as source_handle, os.fdopen(
143
160
  fd, "wb", closefd=True
144
161
  ) as destination_handle:
145
162
  while True:
@@ -152,7 +169,7 @@ class FullFidelityContentStore:
152
169
  destination_handle.flush()
153
170
  os.fsync(destination_handle.fileno())
154
171
 
155
- after = source_path.stat()
172
+ after = source_fs.stat()
156
173
  before_signature = (before.st_size, before.st_mtime_ns)
157
174
  after_signature = (after.st_size, after.st_mtime_ns)
158
175
  if before_signature != after_signature or size != after.st_size:
@@ -162,14 +179,18 @@ class FullFidelityContentStore:
162
179
  suffix = _suffix_for_media_type(media_type)
163
180
  relative = Path(_CONTENT_DIR) / _HASH_ALGORITHM / f"{digest_hex}{suffix}"
164
181
  destination = self.run_root / relative
165
- if destination.exists():
166
- if destination.stat().st_size != size or self._file_sha256(destination) != digest_hex:
182
+ destination_fs = _filesystem_path(destination)
183
+ if destination_fs.exists():
184
+ if (
185
+ destination_fs.stat().st_size != size
186
+ or self._file_sha256(destination_fs) != digest_hex
187
+ ):
167
188
  raise RuntimeError(f"content hash collision at {destination}")
168
189
  else:
169
- temp_path.replace(destination)
190
+ temp_path.replace(destination_fs)
170
191
  if os.name != "nt":
171
192
  try:
172
- destination.chmod(0o600)
193
+ destination_fs.chmod(0o600)
173
194
  except OSError:
174
195
  pass
175
196
  return ContentReference(
@@ -195,19 +216,22 @@ class FullFidelityContentStore:
195
216
  return digest.hexdigest()
196
217
 
197
218
  def _write_once(self, destination: Path, payload: bytes) -> None:
198
- destination.parent.mkdir(parents=True, exist_ok=True)
219
+ destination_fs = _filesystem_path(destination)
220
+ destination_fs.parent.mkdir(parents=True, exist_ok=True)
199
221
  if os.name != "nt":
200
222
  try:
201
- destination.parent.chmod(0o700)
223
+ destination_fs.parent.chmod(0o700)
202
224
  except OSError:
203
225
  pass
204
- if destination.exists():
205
- if destination.read_bytes() != payload:
226
+ if destination_fs.exists():
227
+ if destination_fs.read_bytes() != payload:
206
228
  raise RuntimeError(f"content hash collision at {destination}")
207
229
  return
208
230
 
209
- fd, temp_name = tempfile.mkstemp(prefix=".execweave-content-", dir=destination.parent)
210
- temp_path = Path(temp_name)
231
+ fd, temp_name = tempfile.mkstemp(
232
+ prefix=".execweave-content-", dir=destination_fs.parent
233
+ )
234
+ temp_path = _filesystem_path(Path(temp_name))
211
235
  try:
212
236
  if os.name != "nt":
213
237
  try:
@@ -219,15 +243,15 @@ class FullFidelityContentStore:
219
243
  handle.flush()
220
244
  os.fsync(handle.fileno())
221
245
  try:
222
- temp_path.replace(destination)
246
+ temp_path.replace(destination_fs)
223
247
  except OSError:
224
- if destination.exists() and destination.read_bytes() == payload:
248
+ if destination_fs.exists() and destination_fs.read_bytes() == payload:
225
249
  temp_path.unlink(missing_ok=True)
226
250
  else:
227
251
  raise
228
252
  if os.name != "nt":
229
253
  try:
230
- destination.chmod(0o600)
254
+ destination_fs.chmod(0o600)
231
255
  except OSError:
232
256
  pass
233
257
  finally:
@@ -0,0 +1,159 @@
1
+ """Attribution-safe Cursor GUI launcher hand-off helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import time
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Any, Iterable
10
+
11
+ import psutil
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class CursorHandoff:
16
+ status: str
17
+ snapshot: Any | None = None
18
+ process: psutil.Process | None = None
19
+
20
+
21
+ def is_cursor_invocation(command: Iterable[str]) -> bool:
22
+ values = list(command)
23
+ if not values:
24
+ return False
25
+ name = Path(values[0]).name.lower()
26
+ for suffix in (".exe", ".cmd", ".bat", ".ps1"):
27
+ if name.endswith(suffix):
28
+ name = name[: -len(suffix)]
29
+ break
30
+ return name == "cursor"
31
+
32
+
33
+ def normalized_executable(value: str | None) -> str | None:
34
+ if not value:
35
+ return None
36
+ try:
37
+ return os.path.normcase(str(Path(value).expanduser().resolve(strict=False)))
38
+ except (OSError, RuntimeError, ValueError):
39
+ return os.path.normcase(str(value))
40
+
41
+
42
+ def process_identity(snapshot: Any) -> tuple[int, float]:
43
+ return snapshot.pid, snapshot.create_time
44
+
45
+
46
+ def process_baseline(executable: str | None) -> set[tuple[int, float]]:
47
+ """Return exact PID/create-time identities already using this executable."""
48
+ target = normalized_executable(executable)
49
+ if target is None:
50
+ return set()
51
+ identities: set[tuple[int, float]] = set()
52
+ try:
53
+ processes = psutil.process_iter(["pid", "create_time", "exe"])
54
+ except (OSError, RuntimeError):
55
+ return identities
56
+ for process in processes:
57
+ try:
58
+ info = process.info
59
+ if normalized_executable(info.get("exe")) == target:
60
+ create_time = info.get("create_time")
61
+ if isinstance(create_time, (int, float)):
62
+ identities.add((int(info["pid"]), float(create_time)))
63
+ except (KeyError, OSError, psutil.Error):
64
+ continue
65
+ return identities
66
+
67
+
68
+ def _descends_from(snapshot: Any, root_pid: int, snapshots: dict[int, Any]) -> bool:
69
+ current = snapshot
70
+ visited: set[int] = set()
71
+ while current.ppid > 0 and current.ppid not in visited:
72
+ if current.ppid == root_pid:
73
+ return True
74
+ visited.add(current.ppid)
75
+ parent = snapshots.get(current.ppid)
76
+ if parent is None:
77
+ return False
78
+ current = parent
79
+ return False
80
+
81
+
82
+ def select_handoff_candidate(
83
+ snapshots: Iterable[Any],
84
+ *,
85
+ root: Any,
86
+ executable: str | None,
87
+ baseline: set[tuple[int, float]],
88
+ ) -> CursorHandoff:
89
+ """Select exactly one newly-created descendant of the launcher.
90
+
91
+ The function intentionally abstains when process ancestry or identity is
92
+ ambiguous. It never searches by the string ``Cursor.exe`` alone.
93
+ """
94
+ target = normalized_executable(executable)
95
+ if target is None:
96
+ return CursorHandoff("unattributed_no_executable")
97
+ snapshot_map = {snapshot.pid: snapshot for snapshot in snapshots}
98
+ candidates = []
99
+ for snapshot in snapshot_map.values():
100
+ identity = process_identity(snapshot)
101
+ if identity == process_identity(root) or identity in baseline:
102
+ continue
103
+ if normalized_executable(snapshot.exe) != target:
104
+ continue
105
+ if snapshot.create_time < root.create_time:
106
+ continue
107
+ if not _descends_from(snapshot, root.pid, snapshot_map):
108
+ continue
109
+ try:
110
+ process = psutil.Process(snapshot.pid)
111
+ if process.is_running() and process.status() != psutil.STATUS_ZOMBIE:
112
+ candidates.append((snapshot, process))
113
+ except psutil.Error:
114
+ continue
115
+ if not candidates:
116
+ return CursorHandoff("no_attributed_candidate")
117
+ if len(candidates) != 1:
118
+ return CursorHandoff("ambiguous_candidates")
119
+ snapshot, process = candidates[0]
120
+ return CursorHandoff("handoff", snapshot=snapshot, process=process)
121
+
122
+
123
+ def run_cursor_handoff(
124
+ collector: Any,
125
+ *,
126
+ root_snapshot: Any,
127
+ executable: str,
128
+ baseline: set[tuple[int, float]],
129
+ ) -> None:
130
+ """Keep Live attached to one identity-safe GUI successor until it exits."""
131
+ snapshots = [
132
+ *collector._seen_processes.values(),
133
+ *collector._discovered_processes.values(),
134
+ root_snapshot,
135
+ ]
136
+ handoff = select_handoff_candidate(
137
+ snapshots,
138
+ root=root_snapshot,
139
+ executable=executable,
140
+ baseline=baseline,
141
+ )
142
+ collector._cursor_handoff_info["cursor_handoff_status"] = handoff.status
143
+ if handoff.status != "handoff" or handoff.process is None or handoff.snapshot is None:
144
+ return
145
+
146
+ collector._preserved_processes.add((handoff.snapshot.pid, handoff.snapshot.create_time))
147
+ collector._cursor_handoff_info.update(
148
+ {
149
+ "cursor_handoff_pid": handoff.snapshot.pid,
150
+ "cursor_handoff_create_time": handoff.snapshot.create_time,
151
+ "cursor_handoff_status": "active",
152
+ }
153
+ )
154
+ while collector._process_is_live(handoff.process):
155
+ collector._sample_process_tree(handoff.process)
156
+ time.sleep(collector.poll_interval)
157
+ collector._sample_process_tree(handoff.process)
158
+ collector._mark_disappeared_processes(set())
159
+ collector._cursor_handoff_info["cursor_handoff_status"] = "completed"
@@ -0,0 +1,34 @@
1
+ """Stable public API for third-party framework semantic adapters."""
2
+
3
+ from .autogen import AutoGenAdapter
4
+ from .base import (
5
+ CANONICAL_EVENT_TYPES,
6
+ AdapterCapabilities,
7
+ AdapterContext,
8
+ AgentRecord,
9
+ CaptureMode,
10
+ ContentCapturePolicy,
11
+ ContentWriter,
12
+ EntityRef,
13
+ FrameworkAdapter,
14
+ FrameworkCompatibility,
15
+ MessageRecord,
16
+ ModelCallRecord,
17
+ ProcessRef,
18
+ SemanticWriter,
19
+ TaskRecord,
20
+ ToolCallRecord,
21
+ stable_id,
22
+ )
23
+ from .camel import CAMELAdapter
24
+ from .metagpt import MetaGPTAdapter
25
+ from .registry import AdapterDescriptor, FrameworkAdapterRegistry, default_registry
26
+
27
+ __all__ = [
28
+ "AdapterCapabilities", "AdapterContext", "AdapterDescriptor", "AgentRecord",
29
+ "AutoGenAdapter", "CAMELAdapter", "CANONICAL_EVENT_TYPES", "CaptureMode",
30
+ "ContentCapturePolicy", "ContentWriter", "EntityRef", "FrameworkAdapter",
31
+ "FrameworkAdapterRegistry", "FrameworkCompatibility", "MessageRecord",
32
+ "MetaGPTAdapter", "ModelCallRecord", "ProcessRef", "SemanticWriter",
33
+ "TaskRecord", "ToolCallRecord", "default_registry", "stable_id",
34
+ ]