speclogician 0.0.0b1__py3-none-any.whl → 0.0.0.dev1__py3-none-any.whl

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 (153) hide show
  1. speclogician/agent/funcs.py +29 -0
  2. speclogician/cmd/agent_cmd.py +89 -0
  3. speclogician/cmd/data_cmd.py +24 -0
  4. speclogician/cmd/model_cmd.py +42 -0
  5. speclogician/cmd/overlay_cmd.py +30 -0
  6. speclogician/cmd/scenario_cmd.py +61 -0
  7. speclogician/cmd/state_cmd.py +52 -0
  8. speclogician/data/artifact.py +8 -50
  9. speclogician/data/container.py +18 -384
  10. speclogician/data/mapping.py +18 -17
  11. speclogician/data/refs.py +12 -11
  12. speclogician/data/reports.py +11 -0
  13. speclogician/data/traces.py +15 -6
  14. speclogician/llms/llmtools.py +102 -0
  15. speclogician/llms/overlay.py +264 -0
  16. speclogician/main.py +36 -102
  17. speclogician/modeling/__init__.py +0 -31
  18. speclogician/modeling/component.py +4 -60
  19. speclogician/modeling/conflict.py +5 -19
  20. speclogician/modeling/domain.py +93 -280
  21. speclogician/modeling/model.py +206 -0
  22. speclogician/modeling/predicates.py +20 -22
  23. speclogician/modeling/report.py +33 -0
  24. speclogician/modeling/scenario.py +119 -87
  25. speclogician/sl_cmd.py +76 -0
  26. speclogician/state/change.py +98 -378
  27. speclogician/state/state.py +183 -399
  28. speclogician/tui/box.tcss +10 -0
  29. speclogician/tui/tui.py +131 -0
  30. speclogician/utils/__init__.py +1 -70
  31. speclogician/utils/imx.py +195 -0
  32. speclogician/utils/load.py +25 -147
  33. speclogician/utils/prompt.md +1 -325
  34. speclogician-0.0.0.dev1.dist-info/METADATA +21 -0
  35. speclogician-0.0.0.dev1.dist-info/RECORD +43 -0
  36. speclogician/commands/__init__.py +0 -15
  37. speclogician/commands/cmd_ch.py +0 -616
  38. speclogician/commands/cmd_find.py +0 -256
  39. speclogician/commands/cmd_view.py +0 -202
  40. speclogician/commands/runner.py +0 -149
  41. speclogician/commands/utils.py +0 -101
  42. speclogician/demos/.DS_Store +0 -0
  43. speclogician/demos/cmd_demo.py +0 -278
  44. speclogician/demos/loader.py +0 -135
  45. speclogician/demos/model.py +0 -27
  46. speclogician/demos/runner.py +0 -51
  47. speclogician/logic/__init__.py +0 -11
  48. speclogician/logic/api/__init__.py +0 -29
  49. speclogician/logic/api/client.py +0 -606
  50. speclogician/logic/api/decomp.py +0 -67
  51. speclogician/logic/api/scenario.py +0 -102
  52. speclogician/logic/api/traces.py +0 -59
  53. speclogician/logic/lib/__init__.py +0 -19
  54. speclogician/logic/lib/complement.py +0 -107
  55. speclogician/logic/lib/domain_model.py +0 -59
  56. speclogician/logic/lib/predicates.py +0 -151
  57. speclogician/logic/lib/scenarios.py +0 -369
  58. speclogician/logic/lib/traces.py +0 -114
  59. speclogician/logic/lib/transitions.py +0 -104
  60. speclogician/logic/main.py +0 -246
  61. speclogician/logic/strings.py +0 -194
  62. speclogician/logic/utils.py +0 -135
  63. speclogician/modeling/complement.py +0 -104
  64. speclogician/modeling/spec.py +0 -306
  65. speclogician/modeling/spec_stats.py +0 -39
  66. speclogician/presentation/api.py +0 -244
  67. speclogician/presentation/builders/_links.py +0 -44
  68. speclogician/presentation/builders/container.py +0 -53
  69. speclogician/presentation/builders/data_artifact.py +0 -42
  70. speclogician/presentation/builders/domain.py +0 -54
  71. speclogician/presentation/builders/instances_list.py +0 -38
  72. speclogician/presentation/builders/predicate.py +0 -51
  73. speclogician/presentation/builders/recommendations.py +0 -41
  74. speclogician/presentation/builders/scenario.py +0 -41
  75. speclogician/presentation/builders/scenario_complement.py +0 -82
  76. speclogician/presentation/builders/smart_find.py +0 -39
  77. speclogician/presentation/builders/spec.py +0 -39
  78. speclogician/presentation/builders/state_diff.py +0 -150
  79. speclogician/presentation/builders/state_instance.py +0 -42
  80. speclogician/presentation/builders/state_instance_summary.py +0 -84
  81. speclogician/presentation/builders/trace.py +0 -58
  82. speclogician/presentation/ctx.py +0 -38
  83. speclogician/presentation/models/container.py +0 -44
  84. speclogician/presentation/models/data_artifact.py +0 -33
  85. speclogician/presentation/models/domain.py +0 -50
  86. speclogician/presentation/models/instances_list.py +0 -23
  87. speclogician/presentation/models/predicate.py +0 -60
  88. speclogician/presentation/models/recommendations.py +0 -34
  89. speclogician/presentation/models/scenario.py +0 -31
  90. speclogician/presentation/models/scenario_complement.py +0 -40
  91. speclogician/presentation/models/smart_find.py +0 -34
  92. speclogician/presentation/models/spec.py +0 -32
  93. speclogician/presentation/models/state_diff.py +0 -34
  94. speclogician/presentation/models/state_instance.py +0 -31
  95. speclogician/presentation/models/state_instance_summary.py +0 -102
  96. speclogician/presentation/models/trace.py +0 -42
  97. speclogician/presentation/preview/__init__.py +0 -13
  98. speclogician/presentation/preview/cli.py +0 -50
  99. speclogician/presentation/preview/fixtures/__init__.py +0 -205
  100. speclogician/presentation/preview/fixtures/artifact_container.py +0 -150
  101. speclogician/presentation/preview/fixtures/data_artifact.py +0 -144
  102. speclogician/presentation/preview/fixtures/domain_model.py +0 -162
  103. speclogician/presentation/preview/fixtures/instances_list.py +0 -162
  104. speclogician/presentation/preview/fixtures/predicate.py +0 -184
  105. speclogician/presentation/preview/fixtures/scenario.py +0 -84
  106. speclogician/presentation/preview/fixtures/scenario_complement.py +0 -81
  107. speclogician/presentation/preview/fixtures/smart_find.py +0 -140
  108. speclogician/presentation/preview/fixtures/spec.py +0 -95
  109. speclogician/presentation/preview/fixtures/state_diff.py +0 -158
  110. speclogician/presentation/preview/fixtures/state_instance.py +0 -128
  111. speclogician/presentation/preview/fixtures/state_instance_summary.py +0 -80
  112. speclogician/presentation/preview/fixtures/trace.py +0 -206
  113. speclogician/presentation/preview/registry.py +0 -42
  114. speclogician/presentation/renderers/__init__.py +0 -24
  115. speclogician/presentation/renderers/container.py +0 -136
  116. speclogician/presentation/renderers/data_artifact.py +0 -144
  117. speclogician/presentation/renderers/domain.py +0 -123
  118. speclogician/presentation/renderers/instances_list.py +0 -120
  119. speclogician/presentation/renderers/predicate.py +0 -180
  120. speclogician/presentation/renderers/recommendations.py +0 -90
  121. speclogician/presentation/renderers/scenario.py +0 -94
  122. speclogician/presentation/renderers/scenario_complement.py +0 -59
  123. speclogician/presentation/renderers/smart_find.py +0 -307
  124. speclogician/presentation/renderers/spec.py +0 -105
  125. speclogician/presentation/renderers/state_diff.py +0 -102
  126. speclogician/presentation/renderers/state_instance.py +0 -82
  127. speclogician/presentation/renderers/state_instance_summary.py +0 -143
  128. speclogician/presentation/renderers/trace.py +0 -122
  129. speclogician/shell/app.py +0 -170
  130. speclogician/shell/shell_ch.py +0 -263
  131. speclogician/shell/shell_view.py +0 -153
  132. speclogician/state/change_result.py +0 -32
  133. speclogician/state/diff.py +0 -191
  134. speclogician/state/inst.py +0 -574
  135. speclogician/state/recommendation.py +0 -13
  136. speclogician/state/recommender.py +0 -577
  137. speclogician/state/state_stats.py +0 -133
  138. speclogician/tui/__init__.py +0 -0
  139. speclogician/tui/app.py +0 -257
  140. speclogician/tui/app.tcss +0 -160
  141. speclogician/tui/demo.py +0 -45
  142. speclogician/tui/images/speclogician-full.png +0 -0
  143. speclogician/tui/images/speclogician-minimal.png +0 -0
  144. speclogician/tui/main_screen.py +0 -454
  145. speclogician/tui/splash_screen.py +0 -51
  146. speclogician/tui/stats_screen.py +0 -125
  147. speclogician/utils/testing.py +0 -151
  148. speclogician-0.0.0b1.dist-info/METADATA +0 -116
  149. speclogician-0.0.0b1.dist-info/RECORD +0 -139
  150. /speclogician/{presentation → agent}/__init__.py +0 -0
  151. /speclogician/{presentation/builders → cmd}/__init__.py +0 -0
  152. /speclogician/{presentation/models → llms}/__init__.py +0 -0
  153. {speclogician-0.0.0b1.dist-info → speclogician-0.0.0.dev1.dist-info}/WHEEL +0 -0
@@ -1,428 +1,148 @@
1
1
  #
2
2
  # Imandra Inc.
3
3
  #
4
- # speclogician/state/change.py
4
+ # change.py
5
5
  #
6
6
 
7
- from __future__ import annotations
7
+ from pydantic import BaseModel
8
+ # from typing import Optional
8
9
 
9
- from rich.panel import Panel
10
- from rich.text import Text
11
- from rich.console import Group
12
- from pydantic import BaseModel, Field, computed_field, model_validator
13
- from typing import Literal, Optional
14
-
15
- from ..modeling.domain import PredicateType
16
- from ..modeling.scenario import ScenarioDelta
17
-
18
- ProcessChangeStage = Literal["apply_change", "analyze_change", "calc_diff", "ok"]
19
-
20
- class StateChange(BaseModel):
21
- """ StateChange """
22
-
23
- meta : str | None = None
24
-
25
- @computed_field
26
- @property
27
- def kind(self) -> str:
28
- return self.__class__.__name__
29
-
30
- def short_str(self) -> str:
31
- return f"[bold deep_blue_sky]{self.kind}[/bold deep_blue_sky]"
10
+ class ModelChange(BaseModel):
11
+ """
12
+ """
32
13
 
33
- def __rich__(self) -> Panel:
34
- rows: list[Text] = []
35
- for k, v in self.model_dump(exclude_none=True, exclude={"kind"}).items():
36
- rows.append(Text(f"{k} = {v!r}"))
37
- return Panel(
38
- Group(*rows),
39
- title=f"[italic]{self.__class__.__name__}[/]",
40
- title_align="left",
41
- )
14
+ def short_str(self):
15
+ return ""
42
16
 
43
- # ----------------------------
44
- # Domain Base
45
- # ----------------------------
17
+ def __str__ (self):
18
+ return ""
46
19
 
47
- class DomainModelBaseEdit(StateChange):
48
- """ Edit the base component of domain model """
49
- new_base_src : str = Field(..., description="IML source code of the base component")
20
+ class DomainModelBaseEdit(BaseModel):
21
+ """
22
+ """
23
+ new_base_src : str
50
24
 
51
- def short_str(self) -> str:
52
- return "[bold deep_sky_blue]DomainModelBaseEdit[/bold deep_sky_blue]"
25
+ def short_str(self):
26
+ """ """
27
+ return ''
53
28
 
54
- def __str__ (self) -> str:
29
+ def __str__ (self):
55
30
  return ""
56
31
 
57
- # ----------------------------
58
- # Predicates
59
- # ----------------------------
60
-
61
- class PredicateAdd(StateChange):
62
- """ Add a new predicate """
63
- pred_type : PredicateType = Field(..., description="Predicate add")
64
- pred_name : str = Field(..., description="predicate name (no spaces). no signature.")
65
- pred_src : str = Field(..., description="predicate source code")
32
+ class PredicateAdd(BaseModel):
33
+ """
34
+ """
35
+ pred_type : str
36
+ pred_name : str
37
+ pred_src : str
66
38
 
67
39
  def short_str(self):
68
40
  """ """
69
- return "[bold deep_blue_sky]PredicateAdd[/bold deep_blue_sky]"
41
+ return f''
70
42
 
71
43
  def __str__(self):
72
44
  return ""
73
45
 
74
- class PredicateEdit(StateChange):
75
- """ Edit an existing predicate """
76
- pred_name : str = Field(..., description="Predicate name (no spaces)")
77
- pred_src : str = Field(..., description="Predicate source code. No signature.")
46
+ class PredicateEdit(BaseModel):
47
+ """
48
+ """
49
+ pred_name : str
50
+ pred_src : str
78
51
 
79
52
  def short_str(self):
80
- return "[bold deep_blue_sky]PredicateEdit[/bold deep_blue_sky]: [bold]name[/bold]={self.pred_name}"
53
+ return f'PredicateEdit: name={self.pred_name}'
81
54
 
82
55
  def __str__(self):
83
56
  return f'PredicateEdit: {self.pred_name}'
84
57
 
85
- class PredicateRemove(StateChange):
86
- """ Remove an existing predicate """
87
- pred_name : str = Field(..., description="Predicate name to remove")
58
+ class PredicateRemove(BaseModel):
59
+ """
60
+ """
61
+ pred_name : str
88
62
 
89
- def short_str(self) -> str:
63
+ def short_str(self):
90
64
  return f'PredicateRemove: name = {self.pred_name}'
91
65
 
92
- def __str__(self) -> str:
93
- return 'PredicateRemove'
94
-
95
- # ----------------------------
96
- # Transitions
97
- # ----------------------------
66
+ def __str__(self):
67
+ return "PredicateRemove"
98
68
 
99
- class TransitionAdd(StateChange):
100
- """ Add a new transition function """
101
- trans_name : str = Field(..., description="Transition name")
102
- trans_src : str = Field(..., description="Transition source code. No signature.")
69
+ class TransitionAdd(BaseModel):
70
+ """
71
+ """
72
+ pred_name : str
73
+ pred_src : str
103
74
 
104
- def short_str(self) -> str:
105
- return ''
75
+ def short_str(self):
76
+ return f''
106
77
 
107
- def __str__(self) -> str:
108
- return 'TransitionAdd: '
78
+ def __str__(self):
79
+ return "TransitionAdd: "
109
80
 
110
- class TransitionEdit(StateChange):
111
- """ Edit an existing transition function """
112
- trans_name : str = Field(..., description="Transition name")
113
- trans_src : str = Field(..., description="Updated transition code. No signature.")
81
+ class TransitionEdit(BaseModel):
82
+ """
83
+ """
84
+ tran_name : str
85
+ tran_src : str
114
86
 
115
87
  def short_str(self):
116
- return f"[bold deep_blue_sky]TransitionEdit[/bold deep_blue_sky]: [bold]trans_name[/bold]: {self.trans_name}"
88
+ return f''
117
89
 
118
90
  def __str__(self):
119
91
  return "TransitionEdit: "
120
92
 
121
- class TransitionRemove(StateChange):
122
- """ Remove an existing transition function """
123
- trans_name : str = Field(..., description="Transition name")
93
+ class TransitionRemove(BaseModel):
94
+ """ """
95
+ tran_name : str
124
96
 
125
97
  def short_str(self):
126
- return f"[bold deep_blue_sky]TransitionRemove[/bold deep_blue_sky]: [bold]trans_name[/bold]: {self.trans_name}"
98
+ return ''
127
99
 
128
100
  def __str__(self):
129
101
  return "TransitionRemove: "
130
102
 
131
- # ----------------------------
132
- # Scenarios
133
- # ----------------------------
103
+ class ScenarioAdd(ModelChange):
104
+ """
105
+ Add a new scenario
106
+ """
107
+ name : str
134
108
 
135
- class ScenarioAdd(StateChange):
109
+ def __str__(self):
110
+ return ""
111
+
112
+ class ScenarioEdit(ModelChange):
136
113
  """
137
- Add a new scenario using set-delta semantics.
138
- For creation, deltas must be add-only (remove must be empty).
114
+ Edit a scenario
139
115
  """
140
- scenario_name: str
141
- given: Optional[ScenarioDelta] = None
142
- when: Optional[ScenarioDelta] = None
143
- then: Optional[ScenarioDelta] = None
144
-
145
- @model_validator(mode="after")
146
- def _add_only(self) -> "ScenarioAdd":
147
- for sec_name, delta in (("given", self.given), ("when", self.when), ("then", self.then)):
148
- if delta is not None and not delta.is_add_only():
149
- raise ValueError(f"ScenarioAdd.{sec_name}: 'remove' is not allowed when creating a scenario")
150
- return self
151
-
152
- def short_str(self) -> str:
153
- return f"ScenarioAdd: name={self.scenario_name}"
154
-
155
- Section = Literal["given", "when", "then"]
156
-
157
- class ScenarioEdit(StateChange):
158
- scenario_name: str
159
- given: ScenarioDelta | None = None
160
- when: ScenarioDelta | None = None
161
- then: ScenarioDelta | None = None
162
-
163
- @model_validator(mode="after")
164
- def _must_have_some_delta(self) -> "ScenarioEdit":
165
- deltas = [d for d in (self.given, self.when, self.then) if d is not None]
166
-
167
- if not deltas:
168
- raise ValueError("At least one of given/when/then must be provided.")
169
-
170
- if all(d.is_empty() for d in deltas):
171
- raise ValueError("ScenarioEdit has no effect: all provided deltas are empty.")
172
-
173
- return self
174
-
175
- def short_str(self) -> str:
176
- parts = []
177
- for sec in ("given", "when", "then"):
178
- delta = getattr(self, sec)
179
- if delta:
180
- if delta.add:
181
- parts.append(f"{sec} +{delta.add}")
182
- if delta.remove:
183
- parts.append(f"{sec} -{delta.remove}")
184
- return f"ScenarioStepsEdit[{self.scenario_name}]: " + ", ".join(parts)
185
-
186
- class ScenarioRemove(StateChange):
187
- """ Remove an existing scenario """
188
- scenario_name : str = Field(..., description="Name of the scenario to remove")
189
-
116
+ scenario_name : str
117
+
190
118
  def short_str(self):
191
- return f"[bold deep_blue_sky]ScenarioRemove[/bold deep_blue_sky]: [bold]Name:[/bold]{self.scenario_name}"
192
-
193
- # ----------------------------
194
- # Test traces
195
- # ----------------------------
196
-
197
- class RemoveTraceArtifact(StateChange):
198
- """Remove an existing trace artifact (TestTrace or LogTrace)."""
199
- art_id: str = Field(description="Artifact ID")
200
-
201
- def short_str(self) -> str:
202
- return (
203
- f"[bold deep_blue_sky]RemoveTraceArtifact[/bold deep_blue_sky]: "
204
- f"[bold]ArtID[/bold]: {self.art_id}"
205
- )
206
-
207
- class AddTestTrace(StateChange):
208
- """Add a new TestTrace."""
209
- art_id: str | None = Field(description="Artifact ID")
210
-
211
- # TraceArtifact core
212
- given: str = Field(description="Concrete state value (IML expression)")
213
- when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
214
- then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
215
- time: str = Field(default="", description="Optional timestamp")
216
-
217
- # TestTrace fields
218
- name: str = Field(description="Test case name (not unique)")
219
- filepath: str = Field(default="", description="Original test filepath")
220
- language: Optional[str] = Field(default=None, description="Language of the original test source")
221
- contents: Optional[str] = Field(default=None, description="Original test contents")
222
-
223
- def short_str(self) -> str:
224
- return (
225
- f"[bold deep_blue_sky]AddTestTrace[/bold deep_blue_sky]: "
226
- f"[bold]ArtID[/bold]: {self.art_id}"
227
- )
228
-
229
- class EditTestTrace(StateChange):
230
- """Edit an existing TestTrace (patch semantics: only non-None fields are applied)."""
231
- art_id: str = Field(description="Artifact ID")
232
-
233
- # TraceArtifact core (patch)
234
- given: Optional[str] = Field(default=None, description="Concrete state value (IML expression)")
235
- when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
236
- then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
237
- time: Optional[str] = Field(default=None, description="Optional timestamp")
238
-
239
- # TestTrace fields (patch)
240
- name: Optional[str] = Field(default=None, description="Test case name (not unique)")
241
- filepath: Optional[str] = Field(default=None, description="Original test filepath")
242
- language: Optional[str] = Field(default=None, description="Language of the original test source")
243
- contents: Optional[str] = Field(default=None, description="Original test contents")
244
-
245
- @model_validator(mode="after")
246
- def _must_change_something(self) -> EditTestTrace:
247
- if (
248
- self.given is None
249
- and self.when is None
250
- and self.then is None
251
- and self.time is None
252
- and self.name is None
253
- and self.filepath is None
254
- and self.language is None
255
- and self.contents is None
256
- ):
257
- raise ValueError(
258
- "EditTestTrace must provide at least one of: "
259
- "given, when, then, time, name, filepath, language, or contents"
260
- )
261
- return self
262
-
263
- def short_str(self) -> str:
264
- return (
265
- f"[bold deep_blue_sky]EditTestTrace[/bold deep_blue_sky]: "
266
- f"[bold]ArtID[/bold]: {self.art_id}"
267
- )
268
-
269
- # ----------------------------
270
- # Log traces
271
- # ----------------------------
272
-
273
- class AddLogTrace(StateChange):
274
- """Add a new LogTrace."""
275
- art_id: str | None = Field(description="Artifact ID")
276
-
277
- # TraceArtifact core
278
- given: str = Field(description="Concrete state value (IML expression)")
279
- when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
280
- then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
281
- time: str = Field(default="", description="Optional timestamp")
282
-
283
- # LogTrace fields
284
- filename: str = Field(description="Log filename (not unique)")
285
- contents: str = Field(description="Log entry contents")
286
-
287
- def short_str(self) -> str:
288
- return (
289
- f"[bold deep_blue_sky]AddLogTrace[/bold deep_blue_sky]: "
290
- f"[bold]ArtID[/bold]: {self.art_id}"
291
- )
292
-
293
- class EditLogTrace(StateChange):
294
- """Edit an existing LogTrace (patch semantics: only non-None fields are applied)."""
295
- art_id: str = Field(description="Artifact ID")
296
-
297
- # TraceArtifact core (patch)
298
- given: Optional[str] = Field(default=None, description="Concrete state value (IML expression)")
299
- when: Optional[str] = Field(default=None, description="Optional concrete action value (IML expression)")
300
- then: Optional[str] = Field(default=None, description="Optional resulting state value (IML expression)")
301
- time: Optional[str] = Field(default=None, description="Optional timestamp")
302
-
303
- # LogTrace fields (patch)
304
- filename: Optional[str] = Field(default=None, description="Log filename (not unique)")
305
- contents: Optional[str] = Field(default=None, description="Log entry contents")
306
-
307
- @model_validator(mode="after")
308
- def _must_change_something(self) -> EditLogTrace:
309
- if (
310
- self.given is None
311
- and self.when is None
312
- and self.then is None
313
- and self.time is None
314
- and self.filename is None
315
- and self.contents is None
316
- ):
317
- raise ValueError(
318
- "EditLogTrace must provide at least one of: "
319
- "given, when, then, time, filename, or contents"
320
- )
321
- return self
322
-
323
- def short_str(self) -> str:
324
- return (
325
- f"[bold deep_blue_sky]EditLogTrace[/bold deep_blue_sky]: "
326
- f"[bold]ArtID[/bold]: {self.art_id}"
327
- )
328
-
329
- # ----------------------------
330
- # RemoveDataArtifact
331
- # ----------------------------
332
-
333
- class RemoveDataArtifact(StateChange):
334
- """ Remove an existing data artifact """
335
- art_id: str = Field(description="Artifact ID")
336
- def short_str(self) -> str:
337
- return "[bold deep_blue_sky]RemoveDataArtifact[/bold deep_blue_sky]"
338
-
339
- # ----------------------------
340
- # Documentation references
341
- # ----------------------------
342
-
343
- class AddDocRef(StateChange):
344
- """Add a new documentation reference artifact."""
345
- art_id: str | None = Field(description="Artifact ID")
346
- text: str = Field(description="Documentation text")
347
- meta: str | None = Field(default=None, description="Optional metadata")
348
-
349
- def short_str(self) -> str:
350
- return f"[bold deep_blue_sky]AddDocRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
351
-
352
- class EditDocRef(StateChange):
353
- """Edit an existing DocRef."""
354
- art_id: str = Field(description="Artifact ID")
355
- text: str | None = Field(default=None, description="New documentation text")
356
- meta: str | None = Field(default=None, description="New metadata")
357
-
358
- @model_validator(mode="after")
359
- def _must_change_something(self) -> "EditDocRef":
360
- if self.text is None and self.meta is None:
361
- raise ValueError("EditDocRef must provide at least one of: text or meta")
362
- return self
363
-
364
- def short_str(self) -> str:
365
- return f"[bold deep_blue_sky]EditDocRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
366
-
367
- # ----------------------------
368
- # Source code references
369
- # ----------------------------
370
-
371
- class AddSrcCodeRef(StateChange):
372
- """Add a new source code reference artifact."""
373
- art_id: str | None = Field(description="Artifact ID")
374
- src_code: str = Field(description="Source code")
375
- language: str | None = Field(default=None, description="Programming language")
376
- file_path: str | None = Field(default=None, description="Optional file path")
377
- iml_code: str | None = Field(default=None, description="Optional IML formalization")
378
- meta: str | None = Field(default=None, description="Optional metadata")
379
-
380
- def short_str(self) -> str:
381
- return f"[bold deep_blue_sky]AddSrcCodeRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
119
+ return f''
382
120
 
383
- class EditSrcCodeRef(StateChange):
384
- """Edit an existing SrcCodeRef."""
385
- art_id: str = Field(description="Artifact ID")
386
- src_code: str | None = Field(default=None, description="Updated source code")
387
- language: str | None = Field(default=None, description="Updated language")
388
- file_path: str | None = Field(default=None, description="Updated file path")
389
- iml_code: str | None = Field(default=None, description="Updated IML formalization")
390
- meta: str | None = Field(default=None, description="Updated metadata")
391
-
392
- @model_validator(mode="after")
393
- def _must_change_something(self) -> EditSrcCodeRef:
394
- if (
395
- self.src_code is None
396
- and self.language is None
397
- and self.file_path is None
398
- and self.iml_code is None
399
- and self.meta is None
400
- ):
401
- raise ValueError(
402
- "EditSrcCodeRef must provide at least one of: "
403
- "src_code, language, file_path, iml_code, or meta"
404
- )
405
- return self
406
-
407
- def short_str(self) -> str:
408
- return f"[bold deep_blue_sky]EditSrcCodeRef[/bold deep_blue_sky]: [bold]ArtID[/bold]: {self.art_id}"
409
-
410
- # ----------------------------
411
- # Links in the ArtifactMap
412
- # ----------------------------
413
-
414
- class LinkArtifactsComponents(StateChange):
415
- """ Add a link between a non-executable arifact (e.g. source code or documentation) and a model component """
416
- art_id : str = Field(description="Artifact ID")
417
- comp_name : str = Field(description="Component name")
418
-
419
- def short_str(self) -> str:
420
- return "[bold deep_blue_sky]LinkArtifactComponents[/bold deep_blue_sky]"
421
-
422
- class RemoveArtComponentLink(StateChange):
423
- """ Remove a link between a non-executable arifact (e.g. source code or documentation) and a model component """
424
- art_id : str = Field(description="Artifact ID")
425
- comp_name : str = Field(description="Component name")
426
-
427
- def short_str(self) -> str:
428
- return "[bold deep_blue_sky]RemoveArtComponentLink[/bold deep_blue_sky]"
121
+ def __str__(self):
122
+ return ''
123
+
124
+ class ScenarioRemoved(ModelChange):
125
+ """
126
+ Remove a scenario
127
+ """
128
+ scenario_name : str
129
+
130
+ def short_str(self):
131
+ return ''
132
+
133
+ def __str__(self):
134
+ return ""
135
+
136
+ if __name__ == "__main__":
137
+
138
+ from ..utils import console
139
+
140
+ console.print(ScenarioAdd(name="new_name"))
141
+ console.rule()
142
+
143
+ console.print(ScenarioEdit(scenario_name="hello"))
144
+ console.rule()
145
+
146
+ console.print(ScenarioRemoved(scenario_name=""))
147
+ console.rule()
148
+