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,120 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/renderers/instances_list.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- from rich import box
10
- from rich.panel import Panel
11
- from rich.table import Table, Column
12
- from rich.text import Text
13
-
14
- from speclogician.presentation.ctx import RenderCtx
15
- from speclogician.presentation.models.instances_list import InstancesListPM
16
-
17
-
18
- def _bullet_list(changes: str) -> Text:
19
- """
20
- Render a comma-separated change list as a left-aligned bullet list.
21
- """
22
- if not changes:
23
- return Text("–", style="dim")
24
-
25
- items = [c.strip() for c in changes.split(",") if c.strip()]
26
- if not items:
27
- return Text("–", style="dim")
28
-
29
- txt = Text()
30
- for i, item in enumerate(items):
31
- if i > 0:
32
- txt.append("\n")
33
- txt.append("• ", style="dim")
34
- txt.append(item)
35
- return txt
36
-
37
-
38
- def render_instances_list(pm: InstancesListPM, *, ctx: RenderCtx):
39
- b = box.MINIMAL if ctx.compact else box.SIMPLE
40
-
41
- columns = [
42
- Column(header="State ID", justify="center"),
43
- Column(header="Changes", justify="left"),
44
- Column(header="Domain model", justify="center"),
45
- Column(header="Preds\n# (Errors, Used)", justify="center"),
46
- Column(header="Scenarios\n# (Errors, Used)", justify="center"),
47
- Column(header="Test traces\n# (Formalized, Matched)", justify="center"),
48
- Column(header="Log traces\n# (Formalized, Matched)", justify="center"),
49
- Column(header="Src code arts\n# (Matched)", justify="center"),
50
- Column(header="Doc arts\n# (Matched)", justify="center"),
51
- ]
52
-
53
- t = Table(
54
- *columns,
55
- title="SpecLogician State List",
56
- expand=True,
57
- highlight=True,
58
- show_edge=False,
59
- box=b,
60
- )
61
-
62
- for idx, row in enumerate(pm.rows):
63
- if idx > 0:
64
- t.add_section() # thin separator between instances
65
-
66
- s = row.summary
67
-
68
- # ---- Domain model ----
69
- domain_str = str(getattr(s, "base_status", "unknown"))
70
-
71
- # ---- Predicates (totals) ----
72
- preds_total = int(getattr(s, "num_preds_total", 0) or 0)
73
- preds_err = int(getattr(s, "num_preds_errored", 0) or 0)
74
- preds_used = int(getattr(s, "num_preds_matched", 0) or 0)
75
- preds_str = f"{preds_total} ({preds_err}, {preds_used})"
76
-
77
- # These are also available:
78
- # num_state_preds_total / matched / errored
79
- # num_action_preds_total / matched / errored
80
-
81
- # ---- Scenarios ----
82
- sc_total = int(getattr(s, "num_sc_total", 0) or 0)
83
- sc_missing = int(getattr(s, "num_sc_missing", 0) or 0)
84
- sc_inconsistent = int(getattr(s, "num_sc_inconsistent", 0) or 0)
85
- sc_conflicted = int(getattr(s, "num_sc_conflicted", 0) or 0)
86
-
87
- # "Errors" bucket includes: missing + inconsistent + conflicted
88
- sc_err = sc_missing + sc_inconsistent + sc_conflicted
89
- sc_used = int(getattr(s, "num_sc_matched", 0) or 0)
90
- sc_str = f"{sc_total} ({sc_err}, {sc_used})"
91
-
92
- # ---- Test traces ----
93
- tt_total = int(getattr(s, "num_test_traces_total", 0) or 0)
94
- tt_formal = int(getattr(s, "num_test_traces_logic_good", 0) or 0)
95
- tt_matched = int(getattr(s, "num_test_traces_matched", 0) or 0)
96
- test_str = f"{tt_total} ({tt_formal}, {tt_matched})"
97
-
98
- # ---- Log traces ----
99
- lt_total = int(getattr(s, "num_log_traces_total", 0) or 0)
100
- lt_formal = int(getattr(s, "num_log_traces_logic_good", 0) or 0)
101
- lt_matched = int(getattr(s, "num_log_traces_matched", 0) or 0)
102
- log_str = f"{lt_total} ({lt_formal}, {lt_matched})"
103
-
104
- # ---- Data artifacts ----
105
- src_matched = int(getattr(s, "num_src_code_arts_matched", 0) or 0)
106
- doc_matched = int(getattr(s, "num_doc_arts_matched", 0) or 0)
107
-
108
- t.add_row(
109
- Text(row.state_label, style="bold green" if idx == 0 else ""),
110
- _bullet_list(row.changes),
111
- Text(domain_str),
112
- Text(preds_str),
113
- Text(sc_str),
114
- Text(test_str),
115
- Text(log_str),
116
- Text(str(src_matched)),
117
- Text(str(doc_matched)),
118
- )
119
-
120
- return Panel(t, title="[bold]Instances[/bold]", border_style="magenta")
@@ -1,180 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/renderers/predicate.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- from rich import box
10
- from rich.console import Group, RenderableType
11
- from rich.panel import Panel
12
- from rich.syntax import Syntax
13
- from rich.table import Table
14
- from rich.text import Text
15
-
16
- from speclogician.presentation.ctx import RenderCtx
17
- from speclogician.presentation.models.predicate import PredicatePM, TransitionPM
18
- from speclogician.utils import IMLValidity
19
-
20
-
21
- # -----------------------------------------------------------------------------
22
- # small helpers
23
- # -----------------------------------------------------------------------------
24
-
25
- def _meta_table(*, ctx: RenderCtx) -> Table:
26
- b = box.MINIMAL if getattr(ctx, "compact", False) else box.SIMPLE
27
- t = Table(
28
- show_header=False,
29
- box=b,
30
- show_edge=False,
31
- pad_edge=False,
32
- expand=False,
33
- )
34
- # Make keys a bit more prominent than before (consistent with your newer style)
35
- t.add_column(style="bold", no_wrap=True)
36
- t.add_column(justify="left")
37
- return t
38
-
39
-
40
- def _badge(v: IMLValidity) -> Text:
41
- # Normalize: v may be enum; keep it robust
42
- s = (getattr(v, "value", str(v)) or "").lower()
43
-
44
- if s == "valid":
45
- return Text("✓ valid", style="bold green")
46
- if s == "invalid":
47
- return Text("✗ invalid", style="bold red")
48
- if s == "unknown":
49
- return Text("? unknown", style="bold yellow")
50
- return Text(str(getattr(v, "value", v)), style="bold yellow")
51
-
52
-
53
- def _empty(text: str = "∅ empty") -> Text:
54
- return Text(text, style="dim")
55
-
56
-
57
- def _code_block(*, title: str, code: str, lang: str) -> RenderableType:
58
- # word_wrap=True tends to look better in narrow terminals
59
- return Panel(
60
- Syntax(code, lang, line_numbers=False, word_wrap=True),
61
- title=title,
62
- border_style="cyan",
63
- )
64
-
65
-
66
- def _snippet(s: str, *, limit: int = 200) -> str:
67
- s2 = (s or "").strip()
68
- if not s2:
69
- return ""
70
- if len(s2) <= limit:
71
- return s2
72
- return s2[:limit] + "…"
73
-
74
-
75
- def section(t: Table, label: str) -> None:
76
- t.add_row(Text(label, style="italic dim"), Text(""))
77
-
78
- def field(t: Table, name: str, value: Text | str) -> None:
79
- t.add_row(
80
- Text(f" {name}", style="bold"), # ⬅️ indent
81
- value if isinstance(value, Text) else Text(str(value)),
82
- )
83
-
84
-
85
- # -----------------------------------------------------------------------------
86
- # main renderers
87
- # -----------------------------------------------------------------------------
88
-
89
- def render_predicate(pm: PredicatePM, *, ctx: RenderCtx) -> RenderableType:
90
- t = _meta_table(ctx=ctx)
91
-
92
- # ── Identity ─────────────────────────────
93
- section(t, "Identity")
94
- field(t, "name", Text(pm.name or "-", style="bold"))
95
- field(t, "signature", Text(pm.signature or "", style="dim"))
96
- field(t, "type", Text(str(pm.pred_type), style="cyan"))
97
- if ctx.show_ids:
98
- field(t, "comp_id", Text(pm.comp_id or "", style="dim"))
99
- field(t, "updated", Text(pm.last_updated.isoformat(), style="dim"))
100
-
101
- # ── Logic ────────────────────────────────
102
- section(t, "Logic")
103
- field(t, "iml_valid", _badge(pm.is_iml_valid))
104
- if pm.iml_error:
105
- field(t, "iml_error", Text(pm.iml_error, style="red"))
106
-
107
- # ── Connections ──────────────────────────
108
- section(t, "Connections")
109
- field(t, "linked artifacts", pm.links.total)
110
- field(t, "test / log traces", f"{pm.links.test_traces}/{pm.links.log_traces}")
111
- field(t, "doc / src refs", f"{pm.links.doc_refs}/{pm.links.src_code_refs}")
112
- if pm.links.unresolved_ids:
113
- field(t, "unresolved", Text(str(pm.links.unresolved_ids), style="yellow"))
114
-
115
- blocks: list[RenderableType] = [t]
116
-
117
- if ctx.show_code:
118
- blocks.append(Text(""))
119
- blocks.append(
120
- Panel(
121
- Syntax(pm.iml or "(* empty *)", "ocaml", word_wrap=True),
122
- title="iml",
123
- border_style="cyan",
124
- )
125
- )
126
-
127
- border = "blue" if pm.kind == "state_predicate" else "magenta"
128
- return Panel(
129
- Group(*blocks),
130
- title=f"[bold]Predicate[/bold]: {pm.name or '-'}",
131
- border_style=border,
132
- )
133
-
134
-
135
- def render_transition(pm: TransitionPM, *, ctx: RenderCtx) -> RenderableType:
136
- t = _meta_table(ctx=ctx)
137
-
138
- # Section: identity
139
- t.add_row(Text("Identity", style="italic dim"), Text(""))
140
- t.add_row(Text("name"), Text(pm.name or "-", style="bold"))
141
- t.add_row(Text("signature"), Text(pm.signature or "", style="dim"))
142
- if ctx.show_ids:
143
- t.add_row(Text("comp_id"), Text(pm.comp_id or "", style="dim"))
144
- t.add_row(Text("updated"), Text(pm.last_updated.isoformat(), style="dim"))
145
-
146
- # Section: logic
147
- t.add_row(Text("Logic", style="italic dim"), Text(""))
148
- t.add_row(Text("iml_valid"), _badge(pm.is_iml_valid))
149
- if pm.iml_error:
150
- t.add_row(Text("iml_error"), Text(pm.iml_error, style="red"))
151
-
152
- # Section: connections
153
- t.add_row(Text("Connections", style="italic dim"), Text(""))
154
- t.add_row(Text("linked artifacts"), Text(str(pm.links.total)))
155
- t.add_row(Text("test/log traces"), Text(f"{pm.links.test_traces}/{pm.links.log_traces}"))
156
- t.add_row(Text("doc/src refs"), Text(f"{pm.links.doc_refs}/{pm.links.src_code_refs}"))
157
- if pm.links.unresolved_ids:
158
- t.add_row(Text("unresolved"), Text(str(pm.links.unresolved_ids), style="yellow"))
159
-
160
- blocks: list[RenderableType] = [t]
161
-
162
- if ctx.show_code:
163
- blocks.append(Text(""))
164
- blocks.append(
165
- _code_block(
166
- title="iml",
167
- code=(pm.iml or "(* empty *)"),
168
- lang="ocaml",
169
- )
170
- )
171
- else:
172
- snip = _snippet(pm.iml or pm.src_code, limit=120)
173
- blocks.append(Text(""))
174
- blocks.append(Text(f"iml: {snip}" if snip else "iml: ∅", style="dim"))
175
-
176
- return Panel(
177
- Group(*blocks),
178
- title=f"[bold]Transition[/bold]: {pm.name or '-'}",
179
- border_style="green",
180
- )
@@ -1,90 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/renderers/recommendations.py
5
- #
6
-
7
-
8
- from __future__ import annotations
9
-
10
- from rich import box
11
- from rich.console import Group
12
- from rich.panel import Panel
13
- from rich.table import Table
14
- from rich.text import Text
15
-
16
- from speclogician.presentation.ctx import RenderCtx
17
- from speclogician.presentation.models.recommendations import RecommendationsPM, RecommendationPM
18
-
19
-
20
- def _kind_style(kind: str) -> str:
21
- k = (kind or "").lower()
22
- if k == "error":
23
- return "red"
24
- if k == "warning":
25
- return "yellow"
26
- if k == "info":
27
- return "cyan"
28
- return "green" # next
29
-
30
-
31
- def _header(pm: RecommendationsPM) -> Text:
32
- parts = []
33
- if pm.num_error:
34
- parts.append(Text(f"{pm.num_error} error", style="red"))
35
- if pm.num_warning:
36
- parts.append(Text(f"{pm.num_warning} warning", style="yellow"))
37
- if pm.num_next:
38
- parts.append(Text(f"{pm.num_next} next", style="green"))
39
- if pm.num_info:
40
- parts.append(Text(f"{pm.num_info} info", style="cyan"))
41
-
42
- if not parts:
43
- return Text("No recommendations", style="dim")
44
-
45
- out = Text(" • ").join(parts)
46
- return out
47
-
48
-
49
- def _render_item(r: RecommendationPM, *, show_priority: bool) -> list[Text]:
50
- style = _kind_style(r.kind)
51
- left = Text(r.kind.upper(), style=f"bold {style}")
52
- if show_priority:
53
- left.append(f" p{r.priority}", style="dim")
54
- body = Text(r.text)
55
- return [left, body]
56
-
57
-
58
- def render_recommendations(pm: RecommendationsPM, *, ctx: RenderCtx) -> Panel:
59
- b = box.MINIMAL if ctx.compact else box.SIMPLE
60
-
61
- if pm.count == 0:
62
- body = Text("— none —", style="dim")
63
- return Panel(body, title="Recommendations", border_style="dim", box=b)
64
-
65
- show_priority = ctx.show_ids # cheap reuse: if ids are shown, show pri too
66
-
67
- t = Table(
68
- box=b,
69
- pad_edge=False,
70
- show_edge=False,
71
- expand=True,
72
- show_header=False,
73
- )
74
- t.add_column(style="dim", no_wrap=True)
75
- t.add_column(no_wrap=False)
76
-
77
- # In compact mode, show fewer items (but keep deterministic)
78
- items = pm.items
79
- if ctx.compact and len(items) > 8:
80
- items = items[:8]
81
-
82
- for r in items:
83
- left, body = _render_item(r, show_priority=show_priority)
84
- t.add_row(left, body)
85
-
86
- blocks = [t]
87
- # show a small header line if useful
88
- blocks.insert(0, _header(pm))
89
-
90
- return Panel(Group(*blocks), title="Recommendations", border_style="cyan", box=b)
@@ -1,94 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/renderers/scenario.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- from rich import box
10
- from rich.panel import Panel
11
- from rich.table import Table
12
- from rich.text import Text
13
-
14
- from speclogician.presentation.ctx import RenderCtx
15
- from speclogician.presentation.models.scenario import ScenarioPM
16
-
17
-
18
- def _status_style(kind: str) -> str:
19
- k = (kind or "").lower()
20
- if k == "valid":
21
- return "green"
22
- if k == "missing":
23
- return "yellow"
24
- if k == "inconsistent":
25
- return "red"
26
- return "dim"
27
-
28
-
29
- def _section(label: str) -> Text:
30
- return Text(label, style="italic magenta")
31
-
32
-
33
- def _bool_badge(v: bool) -> Text:
34
- return Text("✓" if v else "✗", style=("green" if v else "red"))
35
-
36
-
37
- def _names_block(items: list[str], *, empty: str = "—") -> Text:
38
- """
39
- Render a list of names as plain styled text (no Syntax, no black background).
40
- """
41
- if not items:
42
- return Text(empty, style="dim")
43
-
44
- out = Text()
45
- for i, name in enumerate(items):
46
- if i:
47
- out.append("\n")
48
- out.append("• ", style="dim")
49
- out.append(name, style="cyan")
50
- return out
51
-
52
-
53
- def render_scenario(pm: ScenarioPM, *, ctx: RenderCtx) -> Panel:
54
- status_style = _status_style(pm.status.kind)
55
-
56
- title = Text.assemble(
57
- ("Scenario: ", "bold"),
58
- (pm.name or "(unnamed)", "cyan"),
59
- )
60
-
61
- b = box.MINIMAL if ctx.compact else box.SIMPLE
62
- t = Table(
63
- show_header=False,
64
- box=b,
65
- pad_edge=False,
66
- show_edge=False,
67
- expand=False,
68
- )
69
- t.add_column(style="italic dim", no_wrap=True)
70
- t.add_column(no_wrap=False)
71
-
72
- # optional id
73
- if ctx.show_ids:
74
- t.add_row("comp_id", Text(pm.comp_id, style="dim"))
75
-
76
- # Predicates
77
- t.add_row(_section("Predicates"), Text(""))
78
- t.add_row(" given", _names_block(pm.given))
79
- t.add_row(" when", _names_block(pm.when))
80
- t.add_row(" then", _names_block(pm.then))
81
-
82
- # Checks
83
- t.add_row(_section("Checks"), Text(""))
84
- t.add_row(" given consistent", _bool_badge(pm.given_preds_consistent))
85
- t.add_row(" when consistent", _bool_badge(pm.when_preds_consistent))
86
- t.add_row(" all consistent", _bool_badge(pm.all_preds_consistent))
87
-
88
- # Missing components
89
- if getattr(ctx, "show_missing_components", False) and pm.status.kind == "missing":
90
- t.add_row(_section("Missing"), Text(""))
91
- t.add_row(" predicates", _names_block(pm.status.missing_preds))
92
- t.add_row(" transitions", _names_block(pm.status.missing_trans))
93
-
94
- return Panel(t, title=title, border_style=status_style)
@@ -1,59 +0,0 @@
1
- #
2
- # Imandra Inc.
3
- #
4
- # speclogician/presentation/renderers/scenario_complement.py
5
- #
6
-
7
- from __future__ import annotations
8
-
9
- from rich.console import Group
10
- from rich.panel import Panel
11
- from rich.text import Text
12
-
13
- from speclogician.presentation.ctx import RenderCtx
14
- from speclogician.presentation.models.scenario_complement import ScenarioComplementPM
15
-
16
-
17
- def render_scenario_complement(pm: ScenarioComplementPM, ctx: RenderCtx):
18
- # Header summary
19
- hdr = Text()
20
- hdr.append("Regions: ")
21
- hdr.append(str(pm.count_regions), style="bold")
22
-
23
- if not pm.regions_preview:
24
- return Panel(
25
- Group(hdr, Text("— no regions (or not computed yet) —")),
26
- title="Scenario Complement",
27
- )
28
-
29
- lines = []
30
- for r in pm.regions_preview:
31
- # One-liner summary
32
- line = Text()
33
- line.append(r.fp, style="bold")
34
- line.append(" ")
35
- line.append(f"constraints={r.num_constraints}")
36
-
37
- # If we have extra details, add small indented lines
38
- blocks = [line]
39
- if r.invariant:
40
- blocks.append(Text(f" inv: {r.invariant}"))
41
- if r.constraints_preview:
42
- blocks.append(Text(f" c0: {r.constraints_preview[0]}"))
43
- for c in r.constraints_preview[1:]:
44
- blocks.append(Text(f" {c}"))
45
- if r.model_eval:
46
- blocks.append(Text(f" eval: {r.model_eval}"))
47
- if r.model:
48
- blocks.append(Text(f" model: {r.model}"))
49
-
50
- lines.append(Group(*blocks))
51
-
52
- tail = Text()
53
- if pm.count_regions > len(pm.regions_preview):
54
- tail.append(f"(showing {len(pm.regions_preview)} of {pm.count_regions})", style="dim")
55
-
56
- return Panel(
57
- Group(hdr, *lines, tail),
58
- title="Scenario Complement",
59
- )