rpaforge-core 0.3.6__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 (59) hide show
  1. rpaforge_core-0.3.6/PKG-INFO +90 -0
  2. rpaforge_core-0.3.6/README.md +60 -0
  3. rpaforge_core-0.3.6/pyproject.toml +53 -0
  4. rpaforge_core-0.3.6/setup.cfg +4 -0
  5. rpaforge_core-0.3.6/src/rpaforge/__init__.py +23 -0
  6. rpaforge_core-0.3.6/src/rpaforge/bridge/__init__.py +57 -0
  7. rpaforge_core-0.3.6/src/rpaforge/bridge/__main__.py +8 -0
  8. rpaforge_core-0.3.6/src/rpaforge/bridge/events.py +308 -0
  9. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/__init__.py +180 -0
  10. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/codegen.py +302 -0
  11. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/debugger.py +176 -0
  12. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/desktopui_spy.py +182 -0
  13. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/lifecycle.py +350 -0
  14. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/shared.py +102 -0
  15. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers/webui_spy.py +70 -0
  16. rpaforge_core-0.3.6/src/rpaforge/bridge/handlers.py +11 -0
  17. rpaforge_core-0.3.6/src/rpaforge/bridge/protocol.py +160 -0
  18. rpaforge_core-0.3.6/src/rpaforge/bridge/server.py +339 -0
  19. rpaforge_core-0.3.6/src/rpaforge/codegen/__init__.py +18 -0
  20. rpaforge_core-0.3.6/src/rpaforge/codegen/python_generator.py +897 -0
  21. rpaforge_core-0.3.6/src/rpaforge/core/__init__.py +47 -0
  22. rpaforge_core-0.3.6/src/rpaforge/core/activity.py +359 -0
  23. rpaforge_core-0.3.6/src/rpaforge/core/checkpoint.py +294 -0
  24. rpaforge_core-0.3.6/src/rpaforge/core/diagram_converter.py +293 -0
  25. rpaforge_core-0.3.6/src/rpaforge/core/execution.py +314 -0
  26. rpaforge_core-0.3.6/src/rpaforge/core/executor.py +754 -0
  27. rpaforge_core-0.3.6/src/rpaforge/core/interfaces.py +73 -0
  28. rpaforge_core-0.3.6/src/rpaforge/core/models.py +35 -0
  29. rpaforge_core-0.3.6/src/rpaforge/core/runner.py +538 -0
  30. rpaforge_core-0.3.6/src/rpaforge/core/safe_evaluator.py +328 -0
  31. rpaforge_core-0.3.6/src/rpaforge/core/subprocess_executor.py +221 -0
  32. rpaforge_core-0.3.6/src/rpaforge/core/validation.py +183 -0
  33. rpaforge_core-0.3.6/src/rpaforge/core/validator.py +498 -0
  34. rpaforge_core-0.3.6/src/rpaforge/engine/__init__.py +53 -0
  35. rpaforge_core-0.3.6/src/rpaforge/i18n.py +77 -0
  36. rpaforge_core-0.3.6/src/rpaforge/utils/__init__.py +12 -0
  37. rpaforge_core-0.3.6/src/rpaforge/utils/ipc.py +229 -0
  38. rpaforge_core-0.3.6/src/rpaforge/utils/translator.py +68 -0
  39. rpaforge_core-0.3.6/src/rpaforge/version.py +1 -0
  40. rpaforge_core-0.3.6/src/rpaforge_core.egg-info/PKG-INFO +90 -0
  41. rpaforge_core-0.3.6/src/rpaforge_core.egg-info/SOURCES.txt +57 -0
  42. rpaforge_core-0.3.6/src/rpaforge_core.egg-info/dependency_links.txt +1 -0
  43. rpaforge_core-0.3.6/src/rpaforge_core.egg-info/requires.txt +11 -0
  44. rpaforge_core-0.3.6/src/rpaforge_core.egg-info/top_level.txt +1 -0
  45. rpaforge_core-0.3.6/tests/test_bridge.py +265 -0
  46. rpaforge_core-0.3.6/tests/test_bridge_lifecycle.py +188 -0
  47. rpaforge_core-0.3.6/tests/test_bridge_server.py +449 -0
  48. rpaforge_core-0.3.6/tests/test_cancellation_integration.py +207 -0
  49. rpaforge_core-0.3.6/tests/test_checkpoint.py +419 -0
  50. rpaforge_core-0.3.6/tests/test_circuit_breaker.py +116 -0
  51. rpaforge_core-0.3.6/tests/test_codegen.py +764 -0
  52. rpaforge_core-0.3.6/tests/test_codegen_security.py +96 -0
  53. rpaforge_core-0.3.6/tests/test_debugger_integration.py +314 -0
  54. rpaforge_core-0.3.6/tests/test_diagram_converter.py +58 -0
  55. rpaforge_core-0.3.6/tests/test_engine.py +243 -0
  56. rpaforge_core-0.3.6/tests/test_safe_eval_security.py +21 -0
  57. rpaforge_core-0.3.6/tests/test_safe_evaluator.py +1014 -0
  58. rpaforge_core-0.3.6/tests/test_subprocess_executor.py +166 -0
  59. rpaforge_core-0.3.6/tests/test_validator.py +649 -0
@@ -0,0 +1,90 @@
1
+ Metadata-Version: 2.4
2
+ Name: rpaforge-core
3
+ Version: 0.3.6
4
+ Summary: Native Python execution engine
5
+ Author: RPAForge Contributors
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/chelslava/rpaforge
8
+ Project-URL: Repository, https://github.com/chelslava/rpaforge.git
9
+ Project-URL: Issues, https://github.com/chelslava/rpaforge/issues
10
+ Keywords: rpa,automation,debugger,execution-engine
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: psutil>=5.9.0
22
+ Provides-Extra: subprocess
23
+ Requires-Dist: psutil>=5.9; extra == "subprocess"
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
27
+ Requires-Dist: ruff>=0.15.0; extra == "dev"
28
+ Requires-Dist: mypy>=1.0; extra == "dev"
29
+ Requires-Dist: psutil>=5.9; extra == "dev"
30
+
31
+ [🇷🇺 Русский](README.ru.md)
32
+
33
+ # RPAForge Core
34
+
35
+ [![PyPI version](https://badge.fury.io/py/rpaforge-core.svg)](https://badge.fury.io/py/rpaforge-core)
36
+ [![Python Support](https://img.shields.io/pypi/pyversions/rpaforge-core.svg)](https://pypi.org/project/rpaforge-core/)
37
+ [![License](https://img.shields.io/github/license/chelslava/rpaforge)](LICENSE)
38
+
39
+ Core engine for RPAForge — native Python execution with full debugging, recording, and IPC bridge capabilities.
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ pip install rpaforge-core
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ```python
50
+ from rpaforge import StudioEngine
51
+ from rpaforge_libraries.DesktopUI import DesktopUI
52
+
53
+ engine = StudioEngine()
54
+ engine.executor.register_library("DesktopUI", DesktopUI())
55
+
56
+ builder = engine.create_process("Notepad Automation")
57
+ builder.add_task("Open and Type", [
58
+ ("DesktopUI.Open Application", {"executable": "notepad.exe"}),
59
+ ("DesktopUI.Wait For Window", {"title": "Notepad", "timeout": "10s"}),
60
+ ("DesktopUI.Input Text", {"text": "Hello from RPAForge!"}),
61
+ ("DesktopUI.Close Window", {}),
62
+ ])
63
+
64
+ result = engine.run(builder.build())
65
+ print(f"Status: {result.status}")
66
+ ```
67
+
68
+ ## Features
69
+
70
+ - **Engine**: Native Python execution with topology validation and code generation
71
+ - **Debugger**: Breakpoints, step over/into/out, variable inspection, call stack
72
+ - **Recorder**: Record user actions to automation diagrams
73
+ - **IPC Bridge**: Asyncio JSON-RPC server for Electron ↔ Python communication
74
+
75
+ ## Development
76
+
77
+ ```bash
78
+ # Install in development mode
79
+ pip install -e .
80
+
81
+ # Run tests
82
+ pytest tests/ -v
83
+
84
+ # Format code
85
+ ruff format src/
86
+ ```
87
+
88
+ ## License
89
+
90
+ Apache License 2.0
@@ -0,0 +1,60 @@
1
+ [🇷🇺 Русский](README.ru.md)
2
+
3
+ # RPAForge Core
4
+
5
+ [![PyPI version](https://badge.fury.io/py/rpaforge-core.svg)](https://badge.fury.io/py/rpaforge-core)
6
+ [![Python Support](https://img.shields.io/pypi/pyversions/rpaforge-core.svg)](https://pypi.org/project/rpaforge-core/)
7
+ [![License](https://img.shields.io/github/license/chelslava/rpaforge)](LICENSE)
8
+
9
+ Core engine for RPAForge — native Python execution with full debugging, recording, and IPC bridge capabilities.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install rpaforge-core
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```python
20
+ from rpaforge import StudioEngine
21
+ from rpaforge_libraries.DesktopUI import DesktopUI
22
+
23
+ engine = StudioEngine()
24
+ engine.executor.register_library("DesktopUI", DesktopUI())
25
+
26
+ builder = engine.create_process("Notepad Automation")
27
+ builder.add_task("Open and Type", [
28
+ ("DesktopUI.Open Application", {"executable": "notepad.exe"}),
29
+ ("DesktopUI.Wait For Window", {"title": "Notepad", "timeout": "10s"}),
30
+ ("DesktopUI.Input Text", {"text": "Hello from RPAForge!"}),
31
+ ("DesktopUI.Close Window", {}),
32
+ ])
33
+
34
+ result = engine.run(builder.build())
35
+ print(f"Status: {result.status}")
36
+ ```
37
+
38
+ ## Features
39
+
40
+ - **Engine**: Native Python execution with topology validation and code generation
41
+ - **Debugger**: Breakpoints, step over/into/out, variable inspection, call stack
42
+ - **Recorder**: Record user actions to automation diagrams
43
+ - **IPC Bridge**: Asyncio JSON-RPC server for Electron ↔ Python communication
44
+
45
+ ## Development
46
+
47
+ ```bash
48
+ # Install in development mode
49
+ pip install -e .
50
+
51
+ # Run tests
52
+ pytest tests/ -v
53
+
54
+ # Format code
55
+ ruff format src/
56
+ ```
57
+
58
+ ## License
59
+
60
+ Apache License 2.0
@@ -0,0 +1,53 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "rpaforge-core"
7
+ version = "0.3.6"
8
+ description = "Native Python execution engine"
9
+ readme = "README.md"
10
+ license = {text = "Apache-2.0"}
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "RPAForge Contributors"}
14
+ ]
15
+ keywords = [
16
+ "rpa",
17
+ "automation",
18
+ "debugger",
19
+ "execution-engine",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 3 - Alpha",
23
+ "License :: OSI Approved :: Apache Software License",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = [
32
+ "psutil>=5.9.0",
33
+ ]
34
+
35
+ [project.optional-dependencies]
36
+ subprocess = [
37
+ "psutil>=5.9",
38
+ ]
39
+ dev = [
40
+ "pytest>=8.0",
41
+ "pytest-cov>=4.0",
42
+ "ruff>=0.15.0",
43
+ "mypy>=1.0",
44
+ "psutil>=5.9",
45
+ ]
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/chelslava/rpaforge"
49
+ Repository = "https://github.com/chelslava/rpaforge.git"
50
+ Issues = "https://github.com/chelslava/rpaforge/issues"
51
+
52
+ [tool.setuptools.packages.find]
53
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ """
2
+ RPAForge Core - Open Source RPA Studio Engine.
3
+
4
+ Native Python execution engine without Robot Framework dependencies.
5
+ """
6
+
7
+ from rpaforge.bridge import BridgeServer
8
+ from rpaforge.codegen import CodeGenerator
9
+ from rpaforge.core.runner import (
10
+ Breakpoint,
11
+ ProcessRunner,
12
+ RunnerState,
13
+ StudioEngine,
14
+ )
15
+
16
+ __all__ = [
17
+ "StudioEngine",
18
+ "ProcessRunner",
19
+ "Breakpoint",
20
+ "RunnerState",
21
+ "BridgeServer",
22
+ "CodeGenerator",
23
+ ]
@@ -0,0 +1,57 @@
1
+ """
2
+ RPAForge Bridge Module.
3
+
4
+ IPC communication between Electron UI and Python Engine.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from rpaforge.bridge.events import (
10
+ BreakpointHitEvent,
11
+ BridgeEvent,
12
+ CallStackChangedEvent,
13
+ ErrorEvent,
14
+ EventType,
15
+ KeywordFinishedEvent,
16
+ KeywordStartedEvent,
17
+ LogEvent,
18
+ ProcessFinishedEvent,
19
+ ProcessPausedEvent,
20
+ ProcessResumedEvent,
21
+ ProcessStartedEvent,
22
+ VariablesChangedEvent,
23
+ )
24
+ from rpaforge.bridge.handlers import BridgeHandlers
25
+ from rpaforge.bridge.protocol import (
26
+ JSONRPCError,
27
+ JSONRPCErrorCode,
28
+ JSONRPCNotification,
29
+ JSONRPCRequest,
30
+ JSONRPCResponse,
31
+ parse_message,
32
+ )
33
+ from rpaforge.bridge.server import BridgeServer
34
+
35
+ __all__ = [
36
+ "BridgeServer",
37
+ "BridgeHandlers",
38
+ "BridgeEvent",
39
+ "EventType",
40
+ "LogEvent",
41
+ "BreakpointHitEvent",
42
+ "ProcessStartedEvent",
43
+ "ProcessFinishedEvent",
44
+ "ProcessPausedEvent",
45
+ "ProcessResumedEvent",
46
+ "VariablesChangedEvent",
47
+ "CallStackChangedEvent",
48
+ "KeywordStartedEvent",
49
+ "KeywordFinishedEvent",
50
+ "ErrorEvent",
51
+ "JSONRPCRequest",
52
+ "JSONRPCResponse",
53
+ "JSONRPCNotification",
54
+ "JSONRPCError",
55
+ "JSONRPCErrorCode",
56
+ "parse_message",
57
+ ]
@@ -0,0 +1,8 @@
1
+ """RPAForge Bridge Server module."""
2
+
3
+ from rpaforge.bridge.server import main
4
+
5
+ if __name__ == "__main__":
6
+ import asyncio
7
+
8
+ asyncio.run(main())
@@ -0,0 +1,308 @@
1
+ """
2
+ RPAForge Bridge Events.
3
+
4
+ Event types for IPC communication between Python engine and UI.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from datetime import datetime
11
+ from enum import Enum
12
+ from typing import Any
13
+
14
+
15
+ class EventType(str, Enum):
16
+ """Types of events that can be emitted."""
17
+
18
+ LOG = "log"
19
+ BREAKPOINT_HIT = "breakpointHit"
20
+ PROCESS_STARTED = "processStarted"
21
+ PROCESS_FINISHED = "processFinished"
22
+ PROCESS_STOPPED = "processStopped"
23
+ PROCESS_PAUSED = "processPaused"
24
+ PROCESS_RESUMED = "processResumed"
25
+ VARIABLES_CHANGED = "variablesChanged"
26
+ CALL_STACK_CHANGED = "callStackChanged"
27
+ KEYWORD_STARTED = "keywordStarted"
28
+ KEYWORD_FINISHED = "keywordFinished"
29
+ ERROR = "error"
30
+
31
+
32
+ @dataclass
33
+ class BridgeEvent:
34
+ """Base class for bridge events."""
35
+
36
+ timestamp: datetime = field(default_factory=datetime.now)
37
+
38
+ def to_dict(self) -> dict[str, Any]:
39
+ return {"type": self.event_type(), "timestamp": self.timestamp.isoformat()}
40
+
41
+ @classmethod
42
+ def event_type(cls) -> str:
43
+ """Return the event type string."""
44
+ return "event"
45
+
46
+
47
+ @dataclass
48
+ class LogEvent(BridgeEvent):
49
+ """Event for log messages."""
50
+
51
+ level: str = "info"
52
+ message: str = ""
53
+ source: str | None = None
54
+ run_id: str = ""
55
+
56
+ @classmethod
57
+ def event_type(cls) -> str:
58
+ return EventType.LOG.value
59
+
60
+ def to_dict(self) -> dict[str, Any]:
61
+ result = super().to_dict()
62
+ result.update(
63
+ {
64
+ "level": self.level,
65
+ "message": self.message,
66
+ "runId": self.run_id,
67
+ }
68
+ )
69
+ if self.source:
70
+ result["source"] = self.source
71
+ return result
72
+
73
+
74
+ @dataclass
75
+ class BreakpointHitEvent(BridgeEvent):
76
+ """Event when a breakpoint is hit."""
77
+
78
+ breakpoint_id: str = ""
79
+ file: str = ""
80
+ line: int = 0
81
+ condition: str | None = None
82
+
83
+ @classmethod
84
+ def event_type(cls) -> str:
85
+ return EventType.BREAKPOINT_HIT.value
86
+
87
+ def to_dict(self) -> dict[str, Any]:
88
+ result = super().to_dict()
89
+ result.update(
90
+ {
91
+ "breakpointId": self.breakpoint_id,
92
+ "file": self.file,
93
+ "line": self.line,
94
+ }
95
+ )
96
+ if self.condition:
97
+ result["condition"] = self.condition
98
+ return result
99
+
100
+
101
+ @dataclass
102
+ class ProcessStartedEvent(BridgeEvent):
103
+ """Event when a process starts."""
104
+
105
+ process_id: str = ""
106
+ name: str = ""
107
+ run_id: str = ""
108
+
109
+ @classmethod
110
+ def event_type(cls) -> str:
111
+ return EventType.PROCESS_STARTED.value
112
+
113
+ def to_dict(self) -> dict[str, Any]:
114
+ result = super().to_dict()
115
+ result.update(
116
+ {
117
+ "processId": self.process_id,
118
+ "name": self.name,
119
+ "runId": self.run_id,
120
+ }
121
+ )
122
+ return result
123
+
124
+
125
+ @dataclass
126
+ class ProcessFinishedEvent(BridgeEvent):
127
+ """Event when a process finishes."""
128
+
129
+ status: str = "pass"
130
+ duration: float = 0.0
131
+ message: str | None = None
132
+
133
+ @classmethod
134
+ def event_type(cls) -> str:
135
+ return EventType.PROCESS_FINISHED.value
136
+
137
+ def to_dict(self) -> dict[str, Any]:
138
+ result = super().to_dict()
139
+ result.update(
140
+ {
141
+ "status": self.status,
142
+ "duration": self.duration,
143
+ }
144
+ )
145
+ if self.message:
146
+ result["message"] = self.message
147
+ return result
148
+
149
+
150
+ @dataclass
151
+ class ProcessStoppedEvent(BridgeEvent):
152
+ """Event when a process is stopped/cancelled by user."""
153
+
154
+ reason: str = "user"
155
+
156
+ @classmethod
157
+ def event_type(cls) -> str:
158
+ return EventType.PROCESS_STOPPED.value
159
+
160
+ def to_dict(self) -> dict[str, Any]:
161
+ result = super().to_dict()
162
+ result["reason"] = self.reason
163
+ return result
164
+
165
+
166
+ @dataclass
167
+ class VariablesChangedEvent(BridgeEvent):
168
+ """Event when variables change."""
169
+
170
+ variables: list[dict[str, Any]] = field(default_factory=list)
171
+
172
+ @classmethod
173
+ def event_type(cls) -> str:
174
+ return EventType.VARIABLES_CHANGED.value
175
+
176
+ def to_dict(self) -> dict[str, Any]:
177
+ result = super().to_dict()
178
+ result["variables"] = self.variables
179
+ return result
180
+
181
+
182
+ @dataclass
183
+ class CallStackChangedEvent(BridgeEvent):
184
+ """Event when call stack changes."""
185
+
186
+ call_stack: list[dict[str, Any]] = field(default_factory=list)
187
+
188
+ @classmethod
189
+ def event_type(cls) -> str:
190
+ return EventType.CALL_STACK_CHANGED.value
191
+
192
+ def to_dict(self) -> dict[str, Any]:
193
+ result = super().to_dict()
194
+ result["callStack"] = self.call_stack
195
+ return result
196
+
197
+
198
+ @dataclass
199
+ class KeywordStartedEvent(BridgeEvent):
200
+ """Event when a keyword starts."""
201
+
202
+ name: str = ""
203
+ file: str = ""
204
+ line: int = 0
205
+ args: list[Any] = field(default_factory=list)
206
+
207
+ @classmethod
208
+ def event_type(cls) -> str:
209
+ return EventType.KEYWORD_STARTED.value
210
+
211
+ def to_dict(self) -> dict[str, Any]:
212
+ result = super().to_dict()
213
+ result.update(
214
+ {
215
+ "name": self.name,
216
+ "file": self.file,
217
+ "line": self.line,
218
+ "args": self.args,
219
+ }
220
+ )
221
+ return result
222
+
223
+
224
+ @dataclass
225
+ class KeywordFinishedEvent(BridgeEvent):
226
+ """Event when a keyword finishes."""
227
+
228
+ name: str = ""
229
+ status: str = "pass"
230
+ result: Any | None = None
231
+
232
+ @classmethod
233
+ def event_type(cls) -> str:
234
+ return EventType.KEYWORD_FINISHED.value
235
+
236
+ def to_dict(self) -> dict[str, Any]:
237
+ result = super().to_dict()
238
+ result.update(
239
+ {
240
+ "name": self.name,
241
+ "status": self.status,
242
+ }
243
+ )
244
+ if self.result is not None:
245
+ result["result"] = self.result
246
+ return result
247
+
248
+
249
+ @dataclass
250
+ class ErrorEvent(BridgeEvent):
251
+ """Event for errors."""
252
+
253
+ code: int = 0
254
+ message: str = ""
255
+ details: str | None = None
256
+
257
+ @classmethod
258
+ def event_type(cls) -> str:
259
+ return EventType.ERROR.value
260
+
261
+ def to_dict(self) -> dict[str, Any]:
262
+ result = super().to_dict()
263
+ result.update(
264
+ {
265
+ "code": self.code,
266
+ "message": self.message,
267
+ }
268
+ )
269
+ if self.details:
270
+ result["details"] = self.details
271
+ return result
272
+
273
+
274
+ @dataclass
275
+ class ProcessPausedEvent(BridgeEvent):
276
+ """Event when a process pauses at breakpoint or step."""
277
+
278
+ file: str | None = None
279
+ line: int | None = None
280
+ node_id: str | None = None
281
+ reason: str = "breakpoint"
282
+
283
+ @classmethod
284
+ def event_type(cls) -> str:
285
+ return EventType.PROCESS_PAUSED.value
286
+
287
+ def to_dict(self) -> dict[str, Any]:
288
+ result = super().to_dict()
289
+ result["reason"] = self.reason
290
+ if self.file is not None:
291
+ result["file"] = self.file
292
+ if self.line is not None:
293
+ result["line"] = self.line
294
+ if self.node_id is not None:
295
+ result["nodeId"] = self.node_id
296
+ return result
297
+
298
+
299
+ @dataclass
300
+ class ProcessResumedEvent(BridgeEvent):
301
+ """Event when a process resumes from pause."""
302
+
303
+ @classmethod
304
+ def event_type(cls) -> str:
305
+ return EventType.PROCESS_RESUMED.value
306
+
307
+ def to_dict(self) -> dict[str, Any]:
308
+ return super().to_dict()