cct-cli 0.7.9.0__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 (325) hide show
  1. calc_terminal/__init__.py +14 -0
  2. calc_terminal/__main__.py +14 -0
  3. calc_terminal/activity.py +1334 -0
  4. calc_terminal/agent.py +3387 -0
  5. calc_terminal/agent_runtime.py +519 -0
  6. calc_terminal/ai_context.py +447 -0
  7. calc_terminal/ai_modes.py +752 -0
  8. calc_terminal/ai_personalization.py +286 -0
  9. calc_terminal/ai_preview_feedback.py +213 -0
  10. calc_terminal/aicore.py +2572 -0
  11. calc_terminal/anim.py +367 -0
  12. calc_terminal/app.py +3685 -0
  13. calc_terminal/art.py +639 -0
  14. calc_terminal/atomsim.py +368 -0
  15. calc_terminal/attachments.py +743 -0
  16. calc_terminal/benchmark_system.py +414 -0
  17. calc_terminal/browser/__init__.py +36 -0
  18. calc_terminal/browser/browser_state.py +346 -0
  19. calc_terminal/browser/devserver.py +176 -0
  20. calc_terminal/browser/engine.py +494 -0
  21. calc_terminal/browser/navigation.py +84 -0
  22. calc_terminal/browser/preview.py +429 -0
  23. calc_terminal/browser/preview_entry.py +95 -0
  24. calc_terminal/browser/project_detector.py +144 -0
  25. calc_terminal/browser/server.py +449 -0
  26. calc_terminal/browser/state.py +75 -0
  27. calc_terminal/browser/watcher.py +99 -0
  28. calc_terminal/browser_gui/__init__.py +1 -0
  29. calc_terminal/browser_gui/__main__.py +3 -0
  30. calc_terminal/browser_gui/launcher.py +173 -0
  31. calc_terminal/browser_gui/playwright_browser.py +117 -0
  32. calc_terminal/browser_gui/qt_browser.py +1501 -0
  33. calc_terminal/browser_gui/webview_browser.py +57 -0
  34. calc_terminal/capabilities/__init__.py +35 -0
  35. calc_terminal/capabilities/adapters/__init__.py +33 -0
  36. calc_terminal/capabilities/adapters/bioinformatics.py +204 -0
  37. calc_terminal/capabilities/adapters/browser_adapter.py +205 -0
  38. calc_terminal/capabilities/adapters/filesystem.py +206 -0
  39. calc_terminal/capabilities/adapters/git_adapter.py +202 -0
  40. calc_terminal/capabilities/adapters/jupyter_adapter.py +138 -0
  41. calc_terminal/capabilities/adapters/ml_frameworks.py +158 -0
  42. calc_terminal/capabilities/adapters/platforms.py +200 -0
  43. calc_terminal/capabilities/adapters/python_exec.py +93 -0
  44. calc_terminal/capabilities/adapters/quantum_adapter.py +150 -0
  45. calc_terminal/capabilities/adapters/scientific_comp.py +123 -0
  46. calc_terminal/capabilities/adapters/structural_bio.py +161 -0
  47. calc_terminal/capabilities/adapters/terminal.py +99 -0
  48. calc_terminal/capabilities/bus.py +178 -0
  49. calc_terminal/capabilities/discovery.py +207 -0
  50. calc_terminal/capabilities/schema.py +221 -0
  51. calc_terminal/cat.ico +0 -0
  52. calc_terminal/cat_browser.py +2018 -0
  53. calc_terminal/chat_store.py +703 -0
  54. calc_terminal/cli.py +1178 -0
  55. calc_terminal/code_editor.py +640 -0
  56. calc_terminal/collaboration.py +723 -0
  57. calc_terminal/commands_data.py +139 -0
  58. calc_terminal/compatibility_engine.py +352 -0
  59. calc_terminal/compute/__init__.py +31 -0
  60. calc_terminal/compute/fabric.py +350 -0
  61. calc_terminal/config.py +227 -0
  62. calc_terminal/core/__init__.py +41 -0
  63. calc_terminal/core/checkpoint.py +156 -0
  64. calc_terminal/core/input/__init__.py +45 -0
  65. calc_terminal/core/mode_registry.py +300 -0
  66. calc_terminal/core/project_graph.py +172 -0
  67. calc_terminal/core/recovery.py +129 -0
  68. calc_terminal/core/security_layer.py +112 -0
  69. calc_terminal/core/task_graph.py +202 -0
  70. calc_terminal/core/unified_runtime.py +184 -0
  71. calc_terminal/core/verification.py +257 -0
  72. calc_terminal/customization.py +1566 -0
  73. calc_terminal/derivations.py +153 -0
  74. calc_terminal/device_control.py +263 -0
  75. calc_terminal/diagnostics/__init__.py +27 -0
  76. calc_terminal/diagnostics/doctor_engine.py +382 -0
  77. calc_terminal/diagnostics/self_test.py +247 -0
  78. calc_terminal/doctor.py +519 -0
  79. calc_terminal/easter_eggs.py +274 -0
  80. calc_terminal/editor/__init__.py +1 -0
  81. calc_terminal/editor/actions.py +263 -0
  82. calc_terminal/editor/commands.py +160 -0
  83. calc_terminal/editor/shortcuts.py +226 -0
  84. calc_terminal/engine.py +259 -0
  85. calc_terminal/errors.py +120 -0
  86. calc_terminal/event_stream.py +146 -0
  87. calc_terminal/eventbus.py +133 -0
  88. calc_terminal/extensions.py +733 -0
  89. calc_terminal/fallback_cli.py +1321 -0
  90. calc_terminal/first_run.py +265 -0
  91. calc_terminal/fomoji_auth.py +1043 -0
  92. calc_terminal/formulas.py +82 -0
  93. calc_terminal/fs_cache.py +121 -0
  94. calc_terminal/fs_watcher.py +277 -0
  95. calc_terminal/game.py +193 -0
  96. calc_terminal/gen1.py +5 -0
  97. calc_terminal/generators.py +245 -0
  98. calc_terminal/gestures/__init__.py +42 -0
  99. calc_terminal/gestures/bindings.py +175 -0
  100. calc_terminal/gestures/manager.py +477 -0
  101. calc_terminal/goodbye.py +363 -0
  102. calc_terminal/gpu3d.py +290 -0
  103. calc_terminal/graphs.py +358 -0
  104. calc_terminal/hardware_analyzer.py +440 -0
  105. calc_terminal/host/__init__.py +30 -0
  106. calc_terminal/host/browser_manager.py +187 -0
  107. calc_terminal/host/desktop.py +1386 -0
  108. calc_terminal/host/launcher.py +395 -0
  109. calc_terminal/host/terminal.py +279 -0
  110. calc_terminal/identity.py +216 -0
  111. calc_terminal/input/__init__.py +54 -0
  112. calc_terminal/input/capabilities.py +258 -0
  113. calc_terminal/input/focus.py +87 -0
  114. calc_terminal/input/gestures.py +64 -0
  115. calc_terminal/input/pointer.py +114 -0
  116. calc_terminal/input/touch.py +345 -0
  117. calc_terminal/keys.py +84 -0
  118. calc_terminal/live_automation.py +165 -0
  119. calc_terminal/mathtext.py +433 -0
  120. calc_terminal/mcp.py +386 -0
  121. calc_terminal/memory.py +337 -0
  122. calc_terminal/memory_v2.py +479 -0
  123. calc_terminal/metrics.py +333 -0
  124. calc_terminal/mode_detection.py +146 -0
  125. calc_terminal/model.py +2431 -0
  126. calc_terminal/model_router.py +665 -0
  127. calc_terminal/models/__init__.py +0 -0
  128. calc_terminal/models/active_state.py +187 -0
  129. calc_terminal/models/dynamic_registry.py +584 -0
  130. calc_terminal/models/manager.py +781 -0
  131. calc_terminal/models/model_metadata.json +3526 -0
  132. calc_terminal/models/profiles.py +194 -0
  133. calc_terminal/models/registry.py +265 -0
  134. calc_terminal/models/schema.py +197 -0
  135. calc_terminal/models/validator.py +287 -0
  136. calc_terminal/models/verification_engine.py +368 -0
  137. calc_terminal/native_picker.py +215 -0
  138. calc_terminal/ollama_catalog.py +279 -0
  139. calc_terminal/ollama_download.py +233 -0
  140. calc_terminal/orchestrator.py +304 -0
  141. calc_terminal/package_research.py +322 -0
  142. calc_terminal/packages.py +1024 -0
  143. calc_terminal/pc_specs.py +116 -0
  144. calc_terminal/permissions.py +334 -0
  145. calc_terminal/pet.py +106 -0
  146. calc_terminal/pipeline.py +505 -0
  147. calc_terminal/platform/__init__.py +491 -0
  148. calc_terminal/platform/desktop.py +491 -0
  149. calc_terminal/platform/web.py +781 -0
  150. calc_terminal/preview/__init__.py +1 -0
  151. calc_terminal/preview/dev_server.py +303 -0
  152. calc_terminal/preview/diagnostics.py +131 -0
  153. calc_terminal/preview/live_reload.py +66 -0
  154. calc_terminal/preview/manager.py +129 -0
  155. calc_terminal/project_stats.py +209 -0
  156. calc_terminal/projects.py +328 -0
  157. calc_terminal/providers/__init__.py +0 -0
  158. calc_terminal/providers/adapters/__init__.py +80 -0
  159. calc_terminal/providers/adapters/anthropic_adapter.py +127 -0
  160. calc_terminal/providers/adapters/base.py +106 -0
  161. calc_terminal/providers/adapters/chinese_adapters.py +420 -0
  162. calc_terminal/providers/adapters/gemini_adapter.py +101 -0
  163. calc_terminal/providers/adapters/ollama_adapter.py +83 -0
  164. calc_terminal/providers/adapters/openai_adapter.py +159 -0
  165. calc_terminal/providers/adapters/other_adapters.py +246 -0
  166. calc_terminal/providers/anthropic_provider.py +172 -0
  167. calc_terminal/providers/auto_update.py +416 -0
  168. calc_terminal/providers/base_provider.py +105 -0
  169. calc_terminal/providers/discovery_manager.py +207 -0
  170. calc_terminal/providers/gemini_provider.py +178 -0
  171. calc_terminal/providers/lifecycle.py +767 -0
  172. calc_terminal/providers/ollama_adapter.py +707 -0
  173. calc_terminal/providers/openai_provider.py +254 -0
  174. calc_terminal/providers/provider_manager.py +1827 -0
  175. calc_terminal/providers/providers.json +4075 -0
  176. calc_terminal/reactionsim.py +279 -0
  177. calc_terminal/registry.py +337 -0
  178. calc_terminal/report.py +162 -0
  179. calc_terminal/research/__init__.py +45 -0
  180. calc_terminal/research/artifact_intel.py +126 -0
  181. calc_terminal/research/data_lineage.py +123 -0
  182. calc_terminal/research/experiment_ledger.py +303 -0
  183. calc_terminal/research/reproducibility.py +131 -0
  184. calc_terminal/resilience/__init__.py +47 -0
  185. calc_terminal/resilience/agent_state.py +121 -0
  186. calc_terminal/resilience/capability_matcher.py +174 -0
  187. calc_terminal/resilience/circuit_breaker.py +158 -0
  188. calc_terminal/resilience/failover_engine.py +230 -0
  189. calc_terminal/resilience/health_monitor.py +192 -0
  190. calc_terminal/resilience/ollama_adapter.py +125 -0
  191. calc_terminal/resilience/orchestrator.py +312 -0
  192. calc_terminal/resilience/types.py +134 -0
  193. calc_terminal/sandbox.py +98 -0
  194. calc_terminal/scires.py +558 -0
  195. calc_terminal/security_scanner.py +126 -0
  196. calc_terminal/session.py +294 -0
  197. calc_terminal/sim3d.py +206 -0
  198. calc_terminal/solver.py +276 -0
  199. calc_terminal/sound.py +127 -0
  200. calc_terminal/task_reports.py +287 -0
  201. calc_terminal/terminal_host.py +201 -0
  202. calc_terminal/terminal_identity.py +411 -0
  203. calc_terminal/test_ai_mode_reliability.py +344 -0
  204. calc_terminal/test_browser.py +368 -0
  205. calc_terminal/test_code_editor_upgrade.py +485 -0
  206. calc_terminal/test_customization.py +1148 -0
  207. calc_terminal/test_customization_ui.py +612 -0
  208. calc_terminal/test_dynamic_registry.py +304 -0
  209. calc_terminal/test_extensions.py +436 -0
  210. calc_terminal/test_overhaul.py +557 -0
  211. calc_terminal/test_project_detect.py +255 -0
  212. calc_terminal/test_root_cause_fix.py +527 -0
  213. calc_terminal/test_stability.py +532 -0
  214. calc_terminal/test_terminal_identity.py +132 -0
  215. calc_terminal/test_v079_speed.py +460 -0
  216. calc_terminal/theme.py +1107 -0
  217. calc_terminal/timeline.py +139 -0
  218. calc_terminal/todos.py +246 -0
  219. calc_terminal/tool_call_normalizer.py +419 -0
  220. calc_terminal/tui.py +104 -0
  221. calc_terminal/ui/__init__.py +8 -0
  222. calc_terminal/ui/activity_panel.py +231 -0
  223. calc_terminal/ui/activity_stream_panel.py +238 -0
  224. calc_terminal/ui/animations.py +122 -0
  225. calc_terminal/ui/app.py +7271 -0
  226. calc_terminal/ui/attach_panel.py +597 -0
  227. calc_terminal/ui/attachments.py +424 -0
  228. calc_terminal/ui/backup_panel.py +810 -0
  229. calc_terminal/ui/browser_shell.py +887 -0
  230. calc_terminal/ui/cat_agent.py +357 -0
  231. calc_terminal/ui/chats_panel.py +899 -0
  232. calc_terminal/ui/command_palette.py +125 -0
  233. calc_terminal/ui/command_palette_modal.py +166 -0
  234. calc_terminal/ui/composer.py +1141 -0
  235. calc_terminal/ui/context_menu.py +197 -0
  236. calc_terminal/ui/conversation.py +1435 -0
  237. calc_terminal/ui/customization_panel.py +1229 -0
  238. calc_terminal/ui/dashboard.py +404 -0
  239. calc_terminal/ui/design_system.py +557 -0
  240. calc_terminal/ui/diff_panel.py +213 -0
  241. calc_terminal/ui/editor.py +2102 -0
  242. calc_terminal/ui/empty_state.py +302 -0
  243. calc_terminal/ui/events.py +487 -0
  244. calc_terminal/ui/extensions_panel.py +815 -0
  245. calc_terminal/ui/footer.py +166 -0
  246. calc_terminal/ui/gestures_panel.py +383 -0
  247. calc_terminal/ui/goodbye_screen.py +100 -0
  248. calc_terminal/ui/header.py +1034 -0
  249. calc_terminal/ui/help_panel.py +254 -0
  250. calc_terminal/ui/live_activities.py +914 -0
  251. calc_terminal/ui/mcp_panel.py +570 -0
  252. calc_terminal/ui/memory_center.py +524 -0
  253. calc_terminal/ui/mode_colors_panel.py +525 -0
  254. calc_terminal/ui/nav_screens.py +747 -0
  255. calc_terminal/ui/ollama_panel.py +536 -0
  256. calc_terminal/ui/palette.py +221 -0
  257. calc_terminal/ui/permission_panel.py +269 -0
  258. calc_terminal/ui/personalization_panel.py +517 -0
  259. calc_terminal/ui/personalize_center.py +1568 -0
  260. calc_terminal/ui/preview_panel.py +441 -0
  261. calc_terminal/ui/resizers.py +402 -0
  262. calc_terminal/ui/sidebar.py +1285 -0
  263. calc_terminal/ui/statusbar.py +168 -0
  264. calc_terminal/ui/theme_css.py +1396 -0
  265. calc_terminal/ui/thinking.py +226 -0
  266. calc_terminal/ui/timeline_panel.py +102 -0
  267. calc_terminal/ui/todo_panel.py +193 -0
  268. calc_terminal/ui/viewport.py +136 -0
  269. calc_terminal/ui/vision_panel.py +489 -0
  270. calc_terminal/ui/welcome_modal.py +343 -0
  271. calc_terminal/ui/widgets.py +160 -0
  272. calc_terminal/ui/workspace.py +831 -0
  273. calc_terminal/viewers/__init__.py +1 -0
  274. calc_terminal/viewers/document_viewer.py +252 -0
  275. calc_terminal/viewers/image_viewer.py +241 -0
  276. calc_terminal/viewers/pdf_viewer.py +203 -0
  277. calc_terminal/viewers/presentation_viewer.py +164 -0
  278. calc_terminal/viewers/registry.py +120 -0
  279. calc_terminal/viewers/spreadsheet_viewer.py +204 -0
  280. calc_terminal/vision/__init__.py +89 -0
  281. calc_terminal/vision/analysis.py +194 -0
  282. calc_terminal/vision/annotations.py +297 -0
  283. calc_terminal/vision/capture.py +171 -0
  284. calc_terminal/vision/context.py +231 -0
  285. calc_terminal/vision/correlation.py +169 -0
  286. calc_terminal/vision/cursor.py +258 -0
  287. calc_terminal/vision/events.py +66 -0
  288. calc_terminal/vision/frame_pipeline.py +259 -0
  289. calc_terminal/vision/priority.py +218 -0
  290. calc_terminal/vision/provider.py +180 -0
  291. calc_terminal/vision/safety.py +149 -0
  292. calc_terminal/vision/session.py +281 -0
  293. calc_terminal/vision/verify.py +162 -0
  294. calc_terminal/vision.py +514 -0
  295. calc_terminal/vscode_integration.py +113 -0
  296. calc_terminal/web/__init__.py +8 -0
  297. calc_terminal/web/cat_runtime.py +710 -0
  298. calc_terminal/web/server.py +2891 -0
  299. calc_terminal/web/static/css/app.css +3152 -0
  300. calc_terminal/web/static/icons/badge-72.png +0 -0
  301. calc_terminal/web/static/icons/cat.ico +0 -0
  302. calc_terminal/web/static/icons/icon-128.png +0 -0
  303. calc_terminal/web/static/icons/icon-144.png +0 -0
  304. calc_terminal/web/static/icons/icon-152.png +0 -0
  305. calc_terminal/web/static/icons/icon-192.png +0 -0
  306. calc_terminal/web/static/icons/icon-384.png +0 -0
  307. calc_terminal/web/static/icons/icon-512.png +0 -0
  308. calc_terminal/web/static/icons/icon-72.png +0 -0
  309. calc_terminal/web/static/icons/icon-96.png +0 -0
  310. calc_terminal/web/static/icons/icon.svg +34 -0
  311. calc_terminal/web/static/icons/new-project.png +0 -0
  312. calc_terminal/web/static/icons/open-project.png +0 -0
  313. calc_terminal/web/static/index.html +734 -0
  314. calc_terminal/web/static/js/app.js +2403 -0
  315. calc_terminal/web/static/manifest.json +88 -0
  316. calc_terminal/web/static/sw.js +230 -0
  317. calc_terminal/workflow_engine.py +769 -0
  318. calc_terminal/workspace.py +593 -0
  319. calc_terminal/workspace_index.py +385 -0
  320. cct_cli-0.7.9.0.dist-info/METADATA +210 -0
  321. cct_cli-0.7.9.0.dist-info/RECORD +325 -0
  322. cct_cli-0.7.9.0.dist-info/WHEEL +5 -0
  323. cct_cli-0.7.9.0.dist-info/entry_points.txt +4 -0
  324. cct_cli-0.7.9.0.dist-info/licenses/LICENSE +21 -0
  325. cct_cli-0.7.9.0.dist-info/top_level.txt +1 -0
calc_terminal/art.py ADDED
@@ -0,0 +1,639 @@
1
+ """
2
+ Showcase ASCII block-art library for Chemistry Calc Terminal.
3
+
4
+ A curated gallery of big block-art pieces built from `█ ▓ ▒ ▀ ▄ ╗ ╔ ║ ╣ ╠` and
5
+ friends — chemistry-themed (flask, atom, molecule, benzene ring, DNA), mascots
6
+ (cat, robot, owl, penguin), decorative dividers, abstract 3D shapes, and
7
+ wordmark banners. Every piece renders through `theme.gradient` + `theme.vpad`,
8
+ so it reuses the existing 24-bit color stack — no new rendering code.
9
+
10
+ Used by:
11
+ * the rotating boot banner (a different piece bounces in each launch)
12
+ * the `/art` browse command (walk the whole gallery)
13
+ * easter eggs (themed reveals with a confetti burst)
14
+ """
15
+
16
+ if __name__ == '__main__':
17
+ print("This is a library file and is not meant to be run directly.")
18
+ print("Please run 'python main.py' or 'python model.py' from the project root directory.")
19
+ import sys
20
+ sys.exit(1)
21
+
22
+ import random
23
+
24
+ from . import theme
25
+
26
+
27
+ # ============================================================ the gallery ==
28
+ # Each value is a list of plain (uncolored) art lines. They're colored at
29
+ # render time by `render()`. Keep widths moderate (<= ~46 cols) so a centered
30
+ # piece fits comfortably inside the app's panel width on an 80-col terminal.
31
+ GALLERY = {
32
+ # ------------------------------------------------ chemistry ----------
33
+ "flask": [
34
+ " _",
35
+ " / \\",
36
+ " | |",
37
+ " | |",
38
+ " / \\",
39
+ " / \\",
40
+ " / ▓▓▓▓▓ \\",
41
+ " / ▓▓▓▓▓▓▓ \\",
42
+ "/▓▓▓▓▓▓▓▓▓▓▓▓▓\\",
43
+ "===============\\",
44
+ " \\___________/",
45
+ ],
46
+ "atom": [
47
+ " ___",
48
+ " ,' `.",
49
+ " / (o) \\ .----.",
50
+ " | .---. | / o \\",
51
+ " \\ \\|/ /----( o )",
52
+ " `-.|-.' \\ o /",
53
+ " .----'|`----. `----'",
54
+ " / o | o \\ |",
55
+ " ( o | o ) (o)",
56
+ " \\ o | o / |",
57
+ " '----'|`----'",
58
+ " |",
59
+ ],
60
+ "molecule": [
61
+ " ___",
62
+ " / \\",
63
+ " | H |",
64
+ " \\___/",
65
+ " |",
66
+ " _____|_____",
67
+ " / \\",
68
+ " | O |",
69
+ " \\___________/",
70
+ " | |",
71
+ " __|__ __|__",
72
+ " / \\ / \\",
73
+ "| H | H |",
74
+ " \\_____/ \\_____/",
75
+ ],
76
+ "benzene": [
77
+ " _____",
78
+ " ,' `.",
79
+ " / . \\",
80
+ " | . . |",
81
+ " \\ . /",
82
+ " `._____,'",
83
+ " / \\",
84
+ " / C₆H₆ \\",
85
+ " /_________\\",
86
+ ],
87
+ "testtube": [
88
+ " ╔═══╗",
89
+ " ║ ║",
90
+ " ║ ║",
91
+ " ║ ║",
92
+ " ║▓▓▓║",
93
+ " ║▓▓▓║",
94
+ " ║▓▓▓║",
95
+ " ║▓▓▓║",
96
+ " ╚═╦═╝",
97
+ " ║",
98
+ " ▼",
99
+ ],
100
+ "crystal": [
101
+ " /\\",
102
+ " / \\",
103
+ " /____\\",
104
+ " /\\ /\\",
105
+ " / \\ / \\",
106
+ " /____\\/____\\",
107
+ " \\ /\\ /",
108
+ " \\ / \\ /",
109
+ " \\/____\\/",
110
+ " ||",
111
+ " ||",
112
+ ],
113
+ "dna": [
114
+ " \\ /",
115
+ " \\ /",
116
+ " | |",
117
+ " / \\",
118
+ " / \\",
119
+ " | |",
120
+ " \\ /",
121
+ " | |",
122
+ " / \\",
123
+ " / \\",
124
+ " | |",
125
+ " \\ /",
126
+ " | |",
127
+ ],
128
+ "beaker": [
129
+ " _______",
130
+ " | |",
131
+ " | |",
132
+ " | |",
133
+ " |\\ /|",
134
+ " | \\ / |",
135
+ " | \\ / |",
136
+ " | V |",
137
+ " |_______|",
138
+ ],
139
+
140
+ # -------------------------------------------------- mascots ----------
141
+ "cat_chemist": [
142
+ " /\\_/\\",
143
+ " ( o.o ) __",
144
+ " > ^ < / \\",
145
+ " / \\ |██|",
146
+ " / \\ \\__/",
147
+ " | C C C |",
148
+ " | H |",
149
+ " \\___O____/",
150
+ ],
151
+ "robot_chemist": [
152
+ " .-------.",
153
+ " | o o |",
154
+ " | [___] |",
155
+ " `-._____.-'",
156
+ " /| |\\",
157
+ " / | ▓▓▓ | \\",
158
+ " | | ▓▓▓ | |",
159
+ " | |_____| |",
160
+ " | _| |_ |",
161
+ " '__|_____|__'",
162
+ ],
163
+ "owl": [
164
+ " ___",
165
+ " /o o\\",
166
+ " ( v )",
167
+ " /| |\\",
168
+ " / |___| \\",
169
+ " / | | \\",
170
+ "| |___| |",
171
+ "|___| |___|",
172
+ " | |",
173
+ " ▢ ▢",
174
+ ],
175
+ "penguin": [
176
+ " ___",
177
+ " / \\",
178
+ " | > < |",
179
+ " | \\_/ |",
180
+ " /_____\\",
181
+ " /\\ /\\",
182
+ " / \\ / \\",
183
+ " /----\\ /----\\",
184
+ "/ V \\",
185
+ "| |",
186
+ "\\_____________/",
187
+ ],
188
+
189
+ # ----------------------------------------------- wordmarks ----------
190
+ "CAT": [
191
+ " ██████╗ ██████╗██╗ ",
192
+ "██╔════╝ ██╔════╝██║ ",
193
+ "██║ ██╗ ██║ ██║ ",
194
+ "██║ ╚██╗██║ ██║ ",
195
+ "╚██████╔╝╚██████╗███████╗",
196
+ " ╚═════╝ ╚═════╝╚══════╝",
197
+ ],
198
+ "CHEM": [
199
+ "██╗ ██╗███████╗███╗ ███╗",
200
+ "██║ ██║██╔════╝████╗ ████║",
201
+ "███████║█████╗ ██╔████╔██║",
202
+ "██╔══██║██╔══╝ ██║╚██╔╝██║",
203
+ "██║ ██║███████╗██║ ╚═╝ ██║",
204
+ "╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝",
205
+ ],
206
+
207
+ # ----------------------------------------------- decorative ----------
208
+ "divider_ornate": [
209
+ "✦━━━━━━━━━━━ ◆ ━━━━━━━━━━━✦",
210
+ " ╭─────────╮ ",
211
+ " │ ⚗ CAT ⚗ │ ",
212
+ " ╰─────────╯ ",
213
+ "✦━━━━━━━━━━━ ◆ ━━━━━━━━━━━✦",
214
+ ],
215
+ "stars_burst": [
216
+ " ✦ * ✧",
217
+ " * ✦ *",
218
+ " ╭───────╮",
219
+ " ✧ │ ✦ ✦ │ ✧",
220
+ " ╰───────╯",
221
+ " * ✦ *",
222
+ " ✧ * ✦",
223
+ ],
224
+ "wave": [
225
+ "▁▂▃▄▅▆▇█▇▆▅▄▃▂▁▂▃▄▅▆▇█▇▆▅▄▃▂▁",
226
+ "▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔",
227
+ " ~ chemistry is just applied waves ~",
228
+ ],
229
+
230
+ # -------------------------------------------------- abstract ----------
231
+ "cube_3d": [
232
+ " +---------+",
233
+ " /| /|",
234
+ "/ | / |",
235
+ "+--+------+ |",
236
+ "| | | +",
237
+ "| +------+--+",
238
+ "| / | /",
239
+ "|/ |/",
240
+ "+---------+",
241
+ ],
242
+ "pyramid": [
243
+ " /\\",
244
+ " / \\",
245
+ " / \\",
246
+ " / \\",
247
+ " / \\",
248
+ " / \\",
249
+ " / \\",
250
+ " /______________\\",
251
+ ],
252
+ "spiral": [
253
+ " ╭─────╮",
254
+ " ╭╯ ╰╮",
255
+ " ╭╯ ╭─╮ ╰╮",
256
+ " │ ╭╯ ╰╮ │",
257
+ " │ ╰─╮ │ │",
258
+ " ╰╮ ╰─╯ ╭╯",
259
+ " ╰╮ ╭╯",
260
+ " ╰─────╯",
261
+ ],
262
+ "dragon": [
263
+ " /\\___/\\",
264
+ " ( o o )",
265
+ " ( =^= )",
266
+ " ) (",
267
+ " ____/ \\____",
268
+ " / \\",
269
+ " ====/ ◣ ◢ \\====",
270
+ " \\__________________/",
271
+ " | | | |",
272
+ " ▤ ▤ ▤ ▤",
273
+ ],
274
+ "rocket": [
275
+ " /\\",
276
+ " / \\",
277
+ " | |",
278
+ " | |",
279
+ " |____|",
280
+ " /| CAT|\\",
281
+ " / |____| \\",
282
+ " / | | \\",
283
+ " | |====| |",
284
+ " \\ | | /",
285
+ " \\_/____\\_/",
286
+ " | || |",
287
+ " * ** *",
288
+ ],
289
+ "heart_molecule": [
290
+ " ◢◣ ◢◣",
291
+ " ◢██◣ ◢██◣",
292
+ " █████████",
293
+ " ███████",
294
+ " █████",
295
+ " ███",
296
+ " █",
297
+ ],
298
+ "wizard": [
299
+ " .-.",
300
+ " / \\",
301
+ " |○ ○ ○|",
302
+ " | ▽ |",
303
+ " \\___/",
304
+ " _|_|_",
305
+ " / \\",
306
+ " / ✦ ✦ \\",
307
+ " | ▓▓▓▓▓ |",
308
+ " \\_______/",
309
+ " | |",
310
+ " _| |_",
311
+ ],
312
+
313
+ # ------------------------------------------------ chemistry (v0.5.6) --
314
+ "bunsen_burner": [
315
+ " ) (",
316
+ " ( )",
317
+ " ) \\ / (",
318
+ " ( )( )",
319
+ " \\_( )_/",
320
+ " | |",
321
+ " ___| |___",
322
+ " / \\",
323
+ " | ▓▓▓▓▓▓▓ |",
324
+ " |_____________|",
325
+ " | |",
326
+ " ___| |___",
327
+ " |___________|",
328
+ ],
329
+ "erlenmeyer": [
330
+ " ___",
331
+ " | |",
332
+ " | |",
333
+ " \\ /",
334
+ " | |",
335
+ " / \\",
336
+ " / ▓▓ \\",
337
+ " / ▓▓▓▓▓▓ \\",
338
+ " /▓▓▓▓▓▓▓▓▓▓\\",
339
+ " /____________\\",
340
+ ],
341
+ "periodic_tile": [
342
+ " ┌─────────┐",
343
+ " │ 29 │",
344
+ " │ │",
345
+ " │ Cu │",
346
+ " │ │",
347
+ " │ Copper │",
348
+ " │ 63.546 │",
349
+ " └─────────┘",
350
+ ],
351
+ "scale_balance": [
352
+ " ___",
353
+ " / \\",
354
+ " ____|_____|____",
355
+ " | | | |",
356
+ " (‾‾‾‾)| |(‾‾‾‾)",
357
+ " \\__/ | | \\__/",
358
+ " | |",
359
+ " __|_____|__",
360
+ " |____________|",
361
+ ],
362
+ "hourglass": [
363
+ " ┌───────┐",
364
+ " \\ /",
365
+ " \\ . /",
366
+ " \\ : /",
367
+ " \\:/",
368
+ " /:\\",
369
+ " / : \\",
370
+ " / . \\",
371
+ " / \\",
372
+ " └───────┘",
373
+ ],
374
+ "lightning_flask": [
375
+ " _",
376
+ " / \\",
377
+ " | |",
378
+ " | | \\",
379
+ " / \\ \\",
380
+ " / ⚡ \\ \\",
381
+ " / ⚡▓▓⚡ \\ /",
382
+ "/▓▓▓▓⚡▓▓▓▓▓▓\\ /",
383
+ "==============\\",
384
+ " \\___________/",
385
+ ],
386
+
387
+ # -------------------------------------------------- mascots (v0.5.6) --
388
+ "phoenix": [
389
+ " \\ ^ /",
390
+ " ) \\ ' / (",
391
+ " `. (o) .'",
392
+ " -==( ('|') )==-",
393
+ " .' /'\\ `.",
394
+ " ( / \\ )",
395
+ " / \\",
396
+ " ' '",
397
+ ],
398
+ "fox_scholar": [
399
+ " /\\ /\\",
400
+ " ( ^.^ )___",
401
+ " > ▽ < / \\",
402
+ " / |███|",
403
+ " / CAT |___|",
404
+ " | ________ |",
405
+ " \\________/‾\\/",
406
+ ],
407
+ "dragonfly": [
408
+ " ══════╤══════",
409
+ " │",
410
+ " ,-(°)-.",
411
+ " ╱══╡ ╞══╲",
412
+ " ╱ └──┬──┘ ╲",
413
+ " │",
414
+ " │",
415
+ " ╱ ╲",
416
+ ],
417
+
418
+ # ----------------------------------------------- decorative (v0.5.6) --
419
+ "circuit_frame": [
420
+ "┌──╴ ╶──┬──╴ ╶──┐",
421
+ "│ ● │ ● │",
422
+ "├──┐ ┌──┴──┐ ┌──┤",
423
+ "│ └──┤ CAT ├──┘ │",
424
+ "├──┐ └─────┘ ┌──┤",
425
+ "│ ● │ ● │",
426
+ "└──╴ ╶──┴──╴ ╶──┘",
427
+ ],
428
+ "molecule_ring": [
429
+ " ●───●",
430
+ " ╱ ╲",
431
+ " ● ●",
432
+ " │ │",
433
+ " ● ●",
434
+ " ╲ ╱",
435
+ " ●───●",
436
+ ],
437
+ "orbit_rings": [
438
+ " . · ˚ ✦ ˚ · .",
439
+ " ⟨ ╭──────────╮ ⟩",
440
+ " ⟨ │ ╭────╮ │ ⟩",
441
+ " ⟨ │ │ ●● │ │ ⟩",
442
+ " ⟨ │ ╰────╯ │ ⟩",
443
+ " ⟨ ╰──────────╯ ⟩",
444
+ " · ˚ ✦ ˚ ·",
445
+ ],
446
+ }
447
+
448
+
449
+ # -------------------------------------------------------------- captions --
450
+ # Short one-line descriptions, shown in the /art browser under each piece.
451
+ CAPTIONS = {
452
+ "flask": "The classic — where every reaction begins.",
453
+ "atom": "Nucleus in the center, electrons everywhere else.",
454
+ "molecule": "H₂O: two hydrogens, one oxygen, infinite importance.",
455
+ "benzene": "C₆H₆ — the aromatic ring that confused chemists for decades.",
456
+ "testtube": "Drop it in. Watch what happens.",
457
+ "crystal": "A lattice, frozen in time.",
458
+ "dna": "The double helix — chemistry that learned to remember.",
459
+ "beaker": "Bigger than a test tube, same science.",
460
+ "cat_chemist": "Schrodinger's lab assistant (may or may not be helpful).",
461
+ "robot_chemist": "Never sleeps, never spills, never stops calculating.",
462
+ "owl": "Wise enough to know the answer is always 'it depends'.",
463
+ "penguin": "Linux's mascot, now doing chemistry.",
464
+ "CAT": "The wordmark, in big blocks.",
465
+ "CHEM": "CHEMISTRY, abbreviated loudly.",
466
+ "divider_ornate": "A flourish for when you need a clean break.",
467
+ "stars_burst": "Pure decoration. Sparkle responsibly.",
468
+ "wave": "Everything is waves, if you zoom out enough.",
469
+ "cube_3d": "A three-dimensional hint, in two dimensions.",
470
+ "pyramid": "Ancient architecture, or a single molecular orbital?",
471
+ "spiral": "Entropy, visualized.",
472
+ "dragon": "Reactive. Approach with care.",
473
+ "rocket": "CAT, ready for liftoff.",
474
+ "heart_molecule":"Bonding is just chemistry with feelings.",
475
+ "wizard": "Casts spells. Also casts equations.",
476
+ "bunsen_burner": "The original heat source. Still undefeated.",
477
+ "erlenmeyer": "The conical one — least likely to spill on a swirl.",
478
+ "periodic_tile": "Element 29. Also this edition's namesake.",
479
+ "scale_balance": "Whatever goes in must come out — mass is stubborn like that.",
480
+ "hourglass": "Half-life, visualized one grain at a time.",
481
+ "lightning_flask": "Exothermic and proud of it.",
482
+ "phoenix": "Combustion with better PR.",
483
+ "fox_scholar": "Quick, clever, mildly caffeinated.",
484
+ "dragonfly": "Symmetry with wings.",
485
+ "circuit_frame": "For when the terminal wants to feel like a lab bench.",
486
+ "molecule_ring": "Minimalist bonding, maximum vibes.",
487
+ "orbit_rings": "Electrons, doing their best impression of planets.",
488
+ }
489
+
490
+
491
+ # ============================================================ boot banners ==
492
+ # A handful of full banners shown one-per-launch (rotating). Each is a tuple
493
+ # (art_lines, subtitle). `random_boot()` picks one at random — different piece
494
+ # every launch. They're larger/wordier than gallery pieces so boot feels grand.
495
+ # v0.7.9.5: Updated branding from "CHEMISTRY CALC TERMINAL" to "CAT"
496
+ BOOT_BANNERS = [
497
+ (GALLERY["flask"], "CAT"),
498
+ (GALLERY["atom"], "CAT"),
499
+ (GALLERY["molecule"], "CAT"),
500
+ (GALLERY["CAT"], "CAT"),
501
+ (GALLERY["benzene"], "CAT"),
502
+ (GALLERY["dna"], "CAT"),
503
+ (GALLERY["crystal"], "CAT"),
504
+ (GALLERY["rocket"], "CAT"),
505
+ ]
506
+
507
+
508
+ # ============================================================ render API ==
509
+ def gallery_names():
510
+ """Ordered list of gallery piece names — the menu for the /art browser.
511
+ Order is fixed (dict insertion order) so the menu is stable across runs."""
512
+ return list(GALLERY.keys())
513
+
514
+
515
+ def info(name):
516
+ """The short caption for a piece (or a fallback if unknown)."""
517
+ return CAPTIONS.get(name, "an ASCII art piece")
518
+
519
+
520
+ def _piece_width(piece):
521
+ return max((theme.vlen(line) for line in piece), default=0)
522
+
523
+
524
+ def render(piece, color_a=theme.CYAN, color_b=theme.PURPLE, bold=True,
525
+ align="center", width=None):
526
+ """Render a list of art lines as a gradient-colored, aligned block.
527
+
528
+ Reuses `theme.gradient` (per-char 24-bit interpolation) and `theme.vpad`
529
+ so there's no new color code here. `align` is "center" (default) or
530
+ "left". `width`, if given, is the column budget to align within; when
531
+ omitted it sizes to the widest line + a 2-col margin.
532
+
533
+ Returns the joined string (newline-separated) — the caller prints it.
534
+ Lines that are pure whitespace are preserved as blank rows so vertical
535
+ spacing in the art is kept intact.
536
+ """
537
+ out = []
538
+ target = width if width is not None else _piece_width(piece) + 2
539
+ for line in piece:
540
+ if line.strip() == "":
541
+ out.append("")
542
+ continue
543
+ colored = theme.gradient(line, color_a, color_b, bold=bold)
544
+ if align == "left":
545
+ out.append(theme.vpad(colored, target, "left"))
546
+ else:
547
+ out.append(theme.vpad(colored, target, "center"))
548
+ return "\n".join(out)
549
+
550
+
551
+ def render_by_name(name, color_a=theme.CYAN, color_b=theme.PURPLE, bold=True,
552
+ align="center", width=None):
553
+ """Convenience: render a gallery piece by its name."""
554
+ piece = GALLERY.get(name)
555
+ if piece is None:
556
+ return ""
557
+ return render(piece, color_a, color_b, bold, align, width)
558
+
559
+
560
+ def random_boot(rng=None):
561
+ """Pick one boot banner at random. Different each launch. Returns the
562
+ (art_lines, subtitle) tuple; the caller animates + prints it.
563
+
564
+ `rng` is accepted for deterministic tests (pass a `random.Random`); the
565
+ default uses the global module RNG so boot genuinely varies per run."""
566
+ pick = rng.choice(BOOT_BANNERS) if rng else random.choice(BOOT_BANNERS)
567
+ return pick
568
+
569
+
570
+ # ---------------------------------------------------------- /art browser --
571
+ # Moved here from the old chatui.py during the chat-UI rewrite — this is
572
+ # an ASCII art gallery viewer, not part of the chat interface, so it
573
+ # belongs with the gallery data it browses rather than in fallback_cli.py.
574
+ # (Not currently wired to a slash command; kept intact rather than
575
+ # deleted so the feature isn't lost.)
576
+ def art_browser():
577
+ """An interactive gallery viewer for this module's ASCII art library.
578
+ Lists every piece in `GALLERY`; picking a number reveals that piece
579
+ with a bouncy gradient animation + its caption. `r` re-rolls to a
580
+ random piece, `q` returns to the caller.
581
+
582
+ Cross-platform: uses blocking `input()` for the menu (works
583
+ everywhere, including Windows where raw single-key reads are flaky).
584
+ """
585
+ from . import engine
586
+ names = gallery_names()
587
+ while True:
588
+ theme.clear_screen()
589
+ print()
590
+ print(theme.center(theme.gradient(" ASCII ART GALLERY ", theme.CYAN, theme.PURPLE, bold=True), engine.WIDTH))
591
+ print(theme.center(theme.faint("browse the showcase — pick a number, or q to exit"), engine.WIDTH))
592
+ print()
593
+ per_col = (len(names) + 1) // 2
594
+ for i in range(per_col):
595
+ left = f" {theme.fg(str(i + 1) + '.', theme.OC_PRIMARY, bold=True)} {names[i]}" if i < len(names) else ""
596
+ j = i + per_col
597
+ right = f" {theme.fg(str(j + 1) + '.', theme.OC_PRIMARY, bold=True)} {names[j]}" if j < len(names) else ""
598
+ gap = " " * max(2, 40 - theme.vlen(left))
599
+ print(theme.text(left) + (gap + theme.text(right) if right else ""))
600
+ print()
601
+ print(theme.faint(" r = random piece q = back to home"))
602
+ try:
603
+ choice = input(theme.badge(" PICK ", theme.BG_INFO) + " ").strip().lower()
604
+ except (EOFError, KeyboardInterrupt):
605
+ print()
606
+ return
607
+
608
+ if choice in ("q", "quit", "exit", "/back", ""):
609
+ return
610
+ if choice in ("r", "random"):
611
+ _show_art_piece(random.choice(names))
612
+ continue
613
+ if choice.isdigit() and 1 <= int(choice) <= len(names):
614
+ _show_art_piece(names[int(choice) - 1])
615
+ continue
616
+
617
+
618
+ def _show_art_piece(name):
619
+ """Reveal one gallery piece with a bouncy animation + caption, then
620
+ wait for Enter before returning to the menu."""
621
+ from . import engine
622
+ from . import anim as _anim
623
+ theme.clear_screen()
624
+ print()
625
+ c1 = random.choice([theme.CYAN, theme.PURPLE, theme.GREEN, theme.OC_PRIMARY, theme.OC_ACCENT])
626
+ c2 = random.choice([theme.PURPLE, theme.CYAN, theme.OC_SECONDARY, theme.ORANGE])
627
+ _anim.confetti_burst(width=engine.WIDTH, count=14)
628
+ print()
629
+ print(theme.center(theme.gradient(name.upper(), c1, c2, bold=True), engine.WIDTH))
630
+ print()
631
+ rendered = render_by_name(name, color_a=c1, color_b=c2)
632
+ _anim.bouncy_reveal(rendered.split("\n"), delay=0.05)
633
+ print()
634
+ print(theme.center(theme.dim(info(name)), engine.WIDTH))
635
+ print()
636
+ try:
637
+ input(theme.faint(" press Enter to return to the gallery\u2026"))
638
+ except (EOFError, KeyboardInterrupt):
639
+ print()