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
@@ -0,0 +1,173 @@
1
+ """
2
+ DEPRECATED โ€” Legacy separate-window browser launcher. NOT the normal Browser Mode.
3
+
4
+ Normal Browser Mode uses calc_terminal.host.desktop.EmbeddedBrowserPane
5
+ (QWebEngineView = real Chromium) instead, which is owned by CAT and runs
6
+ in the same process.
7
+
8
+ This module is kept for backward compatibility only. Do NOT use it as
9
+ the primary browser entry point.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import os
15
+ import sys
16
+ import subprocess
17
+ import pathlib
18
+
19
+ def _has_module(name: str) -> bool:
20
+ try:
21
+ __import__(name)
22
+ return True
23
+ except ImportError:
24
+ return False
25
+
26
+ def _launch_with_pyside(start_url: str) -> int:
27
+ try:
28
+ from .qt_browser import launch_qt_browser
29
+ return launch_qt_browser(start_url)
30
+ except Exception as e:
31
+ print(f"[CAT Browser] PySide6 launch failed: {e}", file=sys.stderr)
32
+ return 1
33
+
34
+ def _launch_with_pyqt(start_url: str) -> int:
35
+ try:
36
+ # Qt browser is written for PySide6, but PyQt6 API is almost identical
37
+ # We try to reuse same file with an alias
38
+ import importlib
39
+ # Force import as PySide6 name if only PyQt6 installed โ€” our qt_browser
40
+ # already handles both via try/except inside
41
+ from .qt_browser import launch_qt_browser
42
+ return launch_qt_browser(start_url)
43
+ except Exception as e:
44
+ print(f"[CAT Browser] PyQt launch failed: {e}", file=sys.stderr)
45
+ return 1
46
+
47
+ def _launch_with_webview(start_url: str) -> int:
48
+ try:
49
+ from .webview_browser import launch_webview_browser
50
+ return launch_webview_browser(start_url)
51
+ except Exception as e:
52
+ print(f"[CAT Browser] pywebview launch failed: {e}", file=sys.stderr)
53
+ return 1
54
+
55
+ def _launch_with_playwright(start_url: str) -> int:
56
+ try:
57
+ from .playwright_browser import launch_playwright_browser
58
+ return launch_playwright_browser(start_url)
59
+ except Exception as e:
60
+ print(f"[CAT Browser] Playwright launch failed: {e}", file=sys.stderr)
61
+ return 1
62
+
63
+ def launch_browser_gui(start_url: str = "about:home", block: bool = True) -> int:
64
+ """
65
+ LEGACY separate-window launcher โ€” DEPRECATED for normal Browser Mode.
66
+
67
+ Per the architecture fix, normal Browser Mode must NOT open a separate OS
68
+ window (webbrowser.open / Chrome / Edge / this launcher's old path).
69
+ It must create/show CAT's EMBEDDED browser view (QWebEngineView child of
70
+ CAT Host, inside the same CAT window that holds the terminal).
71
+
72
+ This function now ONLY delegates to the Host embedded path. If no
73
+ embedded engine is available, it ERRORS with install instructions
74
+ instead of launching a separate Chrome/Edge window (which would violate
75
+ the single-process requirement).
76
+
77
+ Normal code must call: from calc_terminal.host.launcher import launch_cat_host
78
+ """
79
+ # Prefer Host embedded (correct architecture) when available
80
+ try:
81
+ from ..host.launcher import can_launch_host, launch_cat_host, get_host_status # type: ignore
82
+ if can_launch_host():
83
+ # Delegate to Host โ€” Browser INSIDE CAT (embedded QWebEngineView)
84
+ return launch_cat_host(start_browser_url=start_url, start_mode="browser", block=block)
85
+ else:
86
+ st = get_host_status()
87
+ print(f"[CAT Browser] ERROR: No EMBEDDED engine โ€” cannot show Browser INSIDE CAT.", file=sys.stderr)
88
+ print(f"[CAT Browser] {st['reason']}", file=sys.stderr)
89
+ print("[CAT Browser] Install: pip install PySide6 (QWebEngineView child inside CAT Host)", file=sys.stderr)
90
+ print("[CAT Browser] Not launching separate Chrome/Edge (violates architecture).", file=sys.stderr)
91
+ print(f"[CAT Browser] URL that would have rendered inside CAT: {start_url}", file=sys.stderr)
92
+ return 2
93
+ except SystemExit:
94
+ raise
95
+ except Exception as e:
96
+ print(f"[CAT Browser] Host delegate failed ({e}) โ€” not launching external.", file=sys.stderr)
97
+ return 1
98
+ # Legacy separate-window fallback REMOVED โ€” Browser Mode must be embedded.
99
+ # The old _launch_with_* paths are kept below only for diagnostics but are
100
+ # NOT used for normal Browser Mode. Do not re-enable them without fixing
101
+ # the architecture violation.
102
+ # Check for a custom browser backend override
103
+ backend = os.environ.get("CAT_BROWSER_BACKEND", "").lower().strip()
104
+
105
+ # If block=False, spawn a new process so CAT terminal stays usable
106
+ if not block:
107
+ # Spawn detached process: python -m calc_terminal.browser_gui --url <url>
108
+ try:
109
+ cmd = [sys.executable, "-m", "calc_terminal.browser_gui", "--url", start_url]
110
+ kwargs = {}
111
+ if os.name == "nt":
112
+ # DETACHED_PROCESS
113
+ import subprocess as sp
114
+ kwargs["creationflags"] = sp.DETACHED_PROCESS | sp.CREATE_NEW_PROCESS_GROUP # type: ignore
115
+ else:
116
+ kwargs["start_new_session"] = True
117
+ subprocess.Popen(cmd, **kwargs, cwd=os.getcwd())
118
+ return 0
119
+ except Exception as e:
120
+ print(f"[CAT Browser] Failed to spawn browser process: {e}", file=sys.stderr)
121
+ return 1
122
+
123
+ # Block path โ€” try backends in order (or forced)
124
+ if backend in ("pyside", "pyside6"):
125
+ return _launch_with_pyside(start_url)
126
+ if backend in ("pyqt", "pyqt6"):
127
+ return _launch_with_pyqt(start_url)
128
+ if backend in ("playwright", "pw"):
129
+ return _launch_with_playwright(start_url)
130
+ if backend in ("webview", "pywebview"):
131
+ return _launch_with_webview(start_url)
132
+
133
+ # Auto-detect โ€” Playwright is already required for CAT Preview, so it will be available
134
+ # and gives a real Chromium window without extra Qt install
135
+ if _has_module("PySide6"):
136
+ rc = _launch_with_pyside(start_url)
137
+ if rc == 0:
138
+ return rc
139
+ if _has_module("PyQt6"):
140
+ rc = _launch_with_pyqt(start_url)
141
+ if rc == 0:
142
+ return rc
143
+ # Playwright visible window is always available if CAT Preview works โ€” use it as primary fallback
144
+ # (real HTML/CSS/JS, no text extraction)
145
+ if _has_module("playwright"):
146
+ rc = _launch_with_playwright(start_url)
147
+ if rc == 0:
148
+ return rc
149
+ if _has_module("webview"):
150
+ rc = _launch_with_webview(start_url)
151
+ if rc == 0:
152
+ return rc
153
+
154
+ # No GUI backend installed
155
+ print("\n[CAT Browser] No graphical browser backend found.", file=sys.stderr)
156
+ print("Install one of (Playwright already covers Preview, but for standalone window):", file=sys.stderr)
157
+ print(" pip install playwright && playwright install chromium # already for CAT Preview", file=sys.stderr)
158
+ print(" pip install PySide6 # full browser with tabs/toolbar", file=sys.stderr)
159
+ print(" pip install pywebview # lightweight WebView2", file=sys.stderr)
160
+ print("\nAfter installing, run again:", file=sys.stderr)
161
+ print(f" cat browse {start_url}" if start_url != "about:home" else " cat browse", file=sys.stderr)
162
+ return 2
163
+
164
+ def main():
165
+ import argparse
166
+ p = argparse.ArgumentParser(description="CAT Browser โ€” graphical WebView2/Chromium window")
167
+ p.add_argument("--url", default="about:home", help="URL to open")
168
+ p.add_argument("--no-block", action="store_true", help="Don't block, spawn detached")
169
+ args = p.parse_args()
170
+ sys.exit(launch_browser_gui(args.url, block=not args.no_block))
171
+
172
+ if __name__ == "__main__":
173
+ main()
@@ -0,0 +1,117 @@
1
+ """
2
+ Playwright visible browser โ€” fallback when Qt not available.
3
+ Launches a real Chromium window (headless=False) with the URL.
4
+ This is a real browser rendering (HTML/CSS/JS), not text.
5
+ Used for CAT Browser when PySide6/PyQt not installed but Playwright is.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import time
11
+ import sys
12
+
13
+ def launch_playwright_browser(start_url: str = "about:home") -> int:
14
+ try:
15
+ from playwright.sync_api import sync_playwright
16
+ except ImportError:
17
+ print("[CAT Browser] Playwright not installed. Run: pip install playwright && playwright install chromium", file=sys.stderr)
18
+ return 2
19
+
20
+ if start_url in ("about:home", "about:blank", "", None):
21
+ # For new-tab, show a simple CAT page via data URL with real HTML
22
+ html = f"""<!doctype html>
23
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
24
+ <title>CAT โ€” New Tab</title>
25
+ <style>
26
+ body{{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;background:#1a1b26;color:#e8ebfa;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;padding:40px}}
27
+ .wrap{{width:640px;max-width:100%;text-align:center}}
28
+ .logo{{font-size:42px;font-weight:800;letter-spacing:0.08em;margin-bottom:28px}}
29
+ .logo span{{color:#82aaff}}
30
+ .search{{display:flex;align-items:center;background:#1e2030;border:1px solid #737aa2;border-radius:999px;padding:14px 18px}}
31
+ .search input{{flex:1;background:transparent;border:none;outline:none;color:#e8ebfa;font-size:16px}}
32
+ .grid{{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:28px}}
33
+ .card{{background:#1e2030;border:1px solid #737aa2;border-radius:16px;padding:18px;text-decoration:none;color:#e8ebfa;display:flex;flex-direction:column;align-items:center;gap:10px}}
34
+ .card:hover{{border-color:#82aaff}}
35
+ </style>
36
+ <div class="wrap">
37
+ <div class="logo">C<span>A</span>T</div>
38
+ <div class="search"><span>๐Ÿ”</span><input id="q" placeholder="Search or enter a URL" style="flex:1;background:transparent;border:none;outline:none;color:#e8ebfa;font-size:16px;margin-left:10px"></div>
39
+ <div class="grid">
40
+ <a class="card" href="https://youtube.com">โ–ถ<br>YouTube</a>
41
+ <a class="card" href="https://github.com">โฌข<br>GitHub</a>
42
+ <a class="card" href="https://mail.google.com">โœ‰<br>Gmail</a>
43
+ <a class="card" href="http://localhost:3000/connector.html">๐Ÿ”—<br>Fomoji</a>
44
+ </div>
45
+ <div style="margin-top:22px;color:#878caf;font-size:12px">CAT Browser ยท Fomoji-protected ยท Chromium</div>
46
+ </div>
47
+ <script>
48
+ const inp = document.getElementById('q');
49
+ inp.addEventListener('keydown', e=>{{
50
+ if(e.key==='Enter'){{
51
+ const v=inp.value.trim();
52
+ if(!v) return;
53
+ const hasScheme=/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(v);
54
+ const isLocal=v.includes('localhost');
55
+ if(hasScheme||isLocal||(v.includes('.')&&!v.includes(' '))){{
56
+ location.href = hasScheme?v:'https://'+v;
57
+ }} else {{
58
+ location.href='https://www.google.com/search?q='+encodeURIComponent(v)+'&hl=en';
59
+ }}
60
+ }}
61
+ }});
62
+ </script>
63
+ """
64
+ import urllib.parse
65
+ start_url = "data:text/html;charset=utf-8," + urllib.parse.quote(html)
66
+
67
+ # Normalize localhost without scheme
68
+ if start_url.startswith("localhost:"):
69
+ start_url = "http://" + start_url
70
+
71
+ print(f"[CAT Browser] Opening graphical browser (Playwright Chromium) โ†’ {start_url}")
72
+ print("[CAT Browser] Close the browser window to return to CAT.")
73
+ try:
74
+ from pathlib import Path
75
+ user_data_dir = str(Path.home() / ".cat_browser_playwright_data")
76
+ with sync_playwright() as p:
77
+ # headless=False gives a real OS window with full rendering
78
+ # Use persistent context so Fomoji cookies persist between sessions
79
+ context = p.chromium.launch_persistent_context(
80
+ user_data_dir,
81
+ headless=False,
82
+ args=["--disable-blink-features=AutomationControlled"],
83
+ viewport={"width": 1280, "height": 800},
84
+ )
85
+ # For Fomoji, we need to handle new tabs (target=_blank) โ€” open as new page
86
+ def handle_new_page(new_page):
87
+ new_page.wait_for_load_state()
88
+ context.on("page", handle_new_page)
89
+ if context.pages:
90
+ page = context.pages[0]
91
+ else:
92
+ page = context.new_page()
93
+ page.goto(start_url, wait_until="domcontentloaded", timeout=15000)
94
+ # Keep browser open until user closes window
95
+ try:
96
+ while True:
97
+ time.sleep(0.5)
98
+ if len(context.pages) == 0:
99
+ break
100
+ try:
101
+ _ = context.browser
102
+ except Exception:
103
+ break
104
+ except KeyboardInterrupt:
105
+ pass
106
+ finally:
107
+ try:
108
+ context.close()
109
+ except Exception:
110
+ pass
111
+ return 0
112
+ except Exception as e:
113
+ print(f"[CAT Browser] Playwright launch failed: {e}", file=sys.stderr)
114
+ # If chromium not downloaded, try to suggest install
115
+ if "Executable doesn't exist" in str(e) or "chromium" in str(e).lower():
116
+ print("Run: playwright install chromium", file=sys.stderr)
117
+ return 1