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.
- calc_terminal/__init__.py +14 -0
- calc_terminal/__main__.py +14 -0
- calc_terminal/activity.py +1334 -0
- calc_terminal/agent.py +3387 -0
- calc_terminal/agent_runtime.py +519 -0
- calc_terminal/ai_context.py +447 -0
- calc_terminal/ai_modes.py +752 -0
- calc_terminal/ai_personalization.py +286 -0
- calc_terminal/ai_preview_feedback.py +213 -0
- calc_terminal/aicore.py +2572 -0
- calc_terminal/anim.py +367 -0
- calc_terminal/app.py +3685 -0
- calc_terminal/art.py +639 -0
- calc_terminal/atomsim.py +368 -0
- calc_terminal/attachments.py +743 -0
- calc_terminal/benchmark_system.py +414 -0
- calc_terminal/browser/__init__.py +36 -0
- calc_terminal/browser/browser_state.py +346 -0
- calc_terminal/browser/devserver.py +176 -0
- calc_terminal/browser/engine.py +494 -0
- calc_terminal/browser/navigation.py +84 -0
- calc_terminal/browser/preview.py +429 -0
- calc_terminal/browser/preview_entry.py +95 -0
- calc_terminal/browser/project_detector.py +144 -0
- calc_terminal/browser/server.py +449 -0
- calc_terminal/browser/state.py +75 -0
- calc_terminal/browser/watcher.py +99 -0
- calc_terminal/browser_gui/__init__.py +1 -0
- calc_terminal/browser_gui/__main__.py +3 -0
- calc_terminal/browser_gui/launcher.py +173 -0
- calc_terminal/browser_gui/playwright_browser.py +117 -0
- calc_terminal/browser_gui/qt_browser.py +1501 -0
- calc_terminal/browser_gui/webview_browser.py +57 -0
- calc_terminal/capabilities/__init__.py +35 -0
- calc_terminal/capabilities/adapters/__init__.py +33 -0
- calc_terminal/capabilities/adapters/bioinformatics.py +204 -0
- calc_terminal/capabilities/adapters/browser_adapter.py +205 -0
- calc_terminal/capabilities/adapters/filesystem.py +206 -0
- calc_terminal/capabilities/adapters/git_adapter.py +202 -0
- calc_terminal/capabilities/adapters/jupyter_adapter.py +138 -0
- calc_terminal/capabilities/adapters/ml_frameworks.py +158 -0
- calc_terminal/capabilities/adapters/platforms.py +200 -0
- calc_terminal/capabilities/adapters/python_exec.py +93 -0
- calc_terminal/capabilities/adapters/quantum_adapter.py +150 -0
- calc_terminal/capabilities/adapters/scientific_comp.py +123 -0
- calc_terminal/capabilities/adapters/structural_bio.py +161 -0
- calc_terminal/capabilities/adapters/terminal.py +99 -0
- calc_terminal/capabilities/bus.py +178 -0
- calc_terminal/capabilities/discovery.py +207 -0
- calc_terminal/capabilities/schema.py +221 -0
- calc_terminal/cat.ico +0 -0
- calc_terminal/cat_browser.py +2018 -0
- calc_terminal/chat_store.py +703 -0
- calc_terminal/cli.py +1178 -0
- calc_terminal/code_editor.py +640 -0
- calc_terminal/collaboration.py +723 -0
- calc_terminal/commands_data.py +139 -0
- calc_terminal/compatibility_engine.py +352 -0
- calc_terminal/compute/__init__.py +31 -0
- calc_terminal/compute/fabric.py +350 -0
- calc_terminal/config.py +227 -0
- calc_terminal/core/__init__.py +41 -0
- calc_terminal/core/checkpoint.py +156 -0
- calc_terminal/core/input/__init__.py +45 -0
- calc_terminal/core/mode_registry.py +300 -0
- calc_terminal/core/project_graph.py +172 -0
- calc_terminal/core/recovery.py +129 -0
- calc_terminal/core/security_layer.py +112 -0
- calc_terminal/core/task_graph.py +202 -0
- calc_terminal/core/unified_runtime.py +184 -0
- calc_terminal/core/verification.py +257 -0
- calc_terminal/customization.py +1566 -0
- calc_terminal/derivations.py +153 -0
- calc_terminal/device_control.py +263 -0
- calc_terminal/diagnostics/__init__.py +27 -0
- calc_terminal/diagnostics/doctor_engine.py +382 -0
- calc_terminal/diagnostics/self_test.py +247 -0
- calc_terminal/doctor.py +519 -0
- calc_terminal/easter_eggs.py +274 -0
- calc_terminal/editor/__init__.py +1 -0
- calc_terminal/editor/actions.py +263 -0
- calc_terminal/editor/commands.py +160 -0
- calc_terminal/editor/shortcuts.py +226 -0
- calc_terminal/engine.py +259 -0
- calc_terminal/errors.py +120 -0
- calc_terminal/event_stream.py +146 -0
- calc_terminal/eventbus.py +133 -0
- calc_terminal/extensions.py +733 -0
- calc_terminal/fallback_cli.py +1321 -0
- calc_terminal/first_run.py +265 -0
- calc_terminal/fomoji_auth.py +1043 -0
- calc_terminal/formulas.py +82 -0
- calc_terminal/fs_cache.py +121 -0
- calc_terminal/fs_watcher.py +277 -0
- calc_terminal/game.py +193 -0
- calc_terminal/gen1.py +5 -0
- calc_terminal/generators.py +245 -0
- calc_terminal/gestures/__init__.py +42 -0
- calc_terminal/gestures/bindings.py +175 -0
- calc_terminal/gestures/manager.py +477 -0
- calc_terminal/goodbye.py +363 -0
- calc_terminal/gpu3d.py +290 -0
- calc_terminal/graphs.py +358 -0
- calc_terminal/hardware_analyzer.py +440 -0
- calc_terminal/host/__init__.py +30 -0
- calc_terminal/host/browser_manager.py +187 -0
- calc_terminal/host/desktop.py +1386 -0
- calc_terminal/host/launcher.py +395 -0
- calc_terminal/host/terminal.py +279 -0
- calc_terminal/identity.py +216 -0
- calc_terminal/input/__init__.py +54 -0
- calc_terminal/input/capabilities.py +258 -0
- calc_terminal/input/focus.py +87 -0
- calc_terminal/input/gestures.py +64 -0
- calc_terminal/input/pointer.py +114 -0
- calc_terminal/input/touch.py +345 -0
- calc_terminal/keys.py +84 -0
- calc_terminal/live_automation.py +165 -0
- calc_terminal/mathtext.py +433 -0
- calc_terminal/mcp.py +386 -0
- calc_terminal/memory.py +337 -0
- calc_terminal/memory_v2.py +479 -0
- calc_terminal/metrics.py +333 -0
- calc_terminal/mode_detection.py +146 -0
- calc_terminal/model.py +2431 -0
- calc_terminal/model_router.py +665 -0
- calc_terminal/models/__init__.py +0 -0
- calc_terminal/models/active_state.py +187 -0
- calc_terminal/models/dynamic_registry.py +584 -0
- calc_terminal/models/manager.py +781 -0
- calc_terminal/models/model_metadata.json +3526 -0
- calc_terminal/models/profiles.py +194 -0
- calc_terminal/models/registry.py +265 -0
- calc_terminal/models/schema.py +197 -0
- calc_terminal/models/validator.py +287 -0
- calc_terminal/models/verification_engine.py +368 -0
- calc_terminal/native_picker.py +215 -0
- calc_terminal/ollama_catalog.py +279 -0
- calc_terminal/ollama_download.py +233 -0
- calc_terminal/orchestrator.py +304 -0
- calc_terminal/package_research.py +322 -0
- calc_terminal/packages.py +1024 -0
- calc_terminal/pc_specs.py +116 -0
- calc_terminal/permissions.py +334 -0
- calc_terminal/pet.py +106 -0
- calc_terminal/pipeline.py +505 -0
- calc_terminal/platform/__init__.py +491 -0
- calc_terminal/platform/desktop.py +491 -0
- calc_terminal/platform/web.py +781 -0
- calc_terminal/preview/__init__.py +1 -0
- calc_terminal/preview/dev_server.py +303 -0
- calc_terminal/preview/diagnostics.py +131 -0
- calc_terminal/preview/live_reload.py +66 -0
- calc_terminal/preview/manager.py +129 -0
- calc_terminal/project_stats.py +209 -0
- calc_terminal/projects.py +328 -0
- calc_terminal/providers/__init__.py +0 -0
- calc_terminal/providers/adapters/__init__.py +80 -0
- calc_terminal/providers/adapters/anthropic_adapter.py +127 -0
- calc_terminal/providers/adapters/base.py +106 -0
- calc_terminal/providers/adapters/chinese_adapters.py +420 -0
- calc_terminal/providers/adapters/gemini_adapter.py +101 -0
- calc_terminal/providers/adapters/ollama_adapter.py +83 -0
- calc_terminal/providers/adapters/openai_adapter.py +159 -0
- calc_terminal/providers/adapters/other_adapters.py +246 -0
- calc_terminal/providers/anthropic_provider.py +172 -0
- calc_terminal/providers/auto_update.py +416 -0
- calc_terminal/providers/base_provider.py +105 -0
- calc_terminal/providers/discovery_manager.py +207 -0
- calc_terminal/providers/gemini_provider.py +178 -0
- calc_terminal/providers/lifecycle.py +767 -0
- calc_terminal/providers/ollama_adapter.py +707 -0
- calc_terminal/providers/openai_provider.py +254 -0
- calc_terminal/providers/provider_manager.py +1827 -0
- calc_terminal/providers/providers.json +4075 -0
- calc_terminal/reactionsim.py +279 -0
- calc_terminal/registry.py +337 -0
- calc_terminal/report.py +162 -0
- calc_terminal/research/__init__.py +45 -0
- calc_terminal/research/artifact_intel.py +126 -0
- calc_terminal/research/data_lineage.py +123 -0
- calc_terminal/research/experiment_ledger.py +303 -0
- calc_terminal/research/reproducibility.py +131 -0
- calc_terminal/resilience/__init__.py +47 -0
- calc_terminal/resilience/agent_state.py +121 -0
- calc_terminal/resilience/capability_matcher.py +174 -0
- calc_terminal/resilience/circuit_breaker.py +158 -0
- calc_terminal/resilience/failover_engine.py +230 -0
- calc_terminal/resilience/health_monitor.py +192 -0
- calc_terminal/resilience/ollama_adapter.py +125 -0
- calc_terminal/resilience/orchestrator.py +312 -0
- calc_terminal/resilience/types.py +134 -0
- calc_terminal/sandbox.py +98 -0
- calc_terminal/scires.py +558 -0
- calc_terminal/security_scanner.py +126 -0
- calc_terminal/session.py +294 -0
- calc_terminal/sim3d.py +206 -0
- calc_terminal/solver.py +276 -0
- calc_terminal/sound.py +127 -0
- calc_terminal/task_reports.py +287 -0
- calc_terminal/terminal_host.py +201 -0
- calc_terminal/terminal_identity.py +411 -0
- calc_terminal/test_ai_mode_reliability.py +344 -0
- calc_terminal/test_browser.py +368 -0
- calc_terminal/test_code_editor_upgrade.py +485 -0
- calc_terminal/test_customization.py +1148 -0
- calc_terminal/test_customization_ui.py +612 -0
- calc_terminal/test_dynamic_registry.py +304 -0
- calc_terminal/test_extensions.py +436 -0
- calc_terminal/test_overhaul.py +557 -0
- calc_terminal/test_project_detect.py +255 -0
- calc_terminal/test_root_cause_fix.py +527 -0
- calc_terminal/test_stability.py +532 -0
- calc_terminal/test_terminal_identity.py +132 -0
- calc_terminal/test_v079_speed.py +460 -0
- calc_terminal/theme.py +1107 -0
- calc_terminal/timeline.py +139 -0
- calc_terminal/todos.py +246 -0
- calc_terminal/tool_call_normalizer.py +419 -0
- calc_terminal/tui.py +104 -0
- calc_terminal/ui/__init__.py +8 -0
- calc_terminal/ui/activity_panel.py +231 -0
- calc_terminal/ui/activity_stream_panel.py +238 -0
- calc_terminal/ui/animations.py +122 -0
- calc_terminal/ui/app.py +7271 -0
- calc_terminal/ui/attach_panel.py +597 -0
- calc_terminal/ui/attachments.py +424 -0
- calc_terminal/ui/backup_panel.py +810 -0
- calc_terminal/ui/browser_shell.py +887 -0
- calc_terminal/ui/cat_agent.py +357 -0
- calc_terminal/ui/chats_panel.py +899 -0
- calc_terminal/ui/command_palette.py +125 -0
- calc_terminal/ui/command_palette_modal.py +166 -0
- calc_terminal/ui/composer.py +1141 -0
- calc_terminal/ui/context_menu.py +197 -0
- calc_terminal/ui/conversation.py +1435 -0
- calc_terminal/ui/customization_panel.py +1229 -0
- calc_terminal/ui/dashboard.py +404 -0
- calc_terminal/ui/design_system.py +557 -0
- calc_terminal/ui/diff_panel.py +213 -0
- calc_terminal/ui/editor.py +2102 -0
- calc_terminal/ui/empty_state.py +302 -0
- calc_terminal/ui/events.py +487 -0
- calc_terminal/ui/extensions_panel.py +815 -0
- calc_terminal/ui/footer.py +166 -0
- calc_terminal/ui/gestures_panel.py +383 -0
- calc_terminal/ui/goodbye_screen.py +100 -0
- calc_terminal/ui/header.py +1034 -0
- calc_terminal/ui/help_panel.py +254 -0
- calc_terminal/ui/live_activities.py +914 -0
- calc_terminal/ui/mcp_panel.py +570 -0
- calc_terminal/ui/memory_center.py +524 -0
- calc_terminal/ui/mode_colors_panel.py +525 -0
- calc_terminal/ui/nav_screens.py +747 -0
- calc_terminal/ui/ollama_panel.py +536 -0
- calc_terminal/ui/palette.py +221 -0
- calc_terminal/ui/permission_panel.py +269 -0
- calc_terminal/ui/personalization_panel.py +517 -0
- calc_terminal/ui/personalize_center.py +1568 -0
- calc_terminal/ui/preview_panel.py +441 -0
- calc_terminal/ui/resizers.py +402 -0
- calc_terminal/ui/sidebar.py +1285 -0
- calc_terminal/ui/statusbar.py +168 -0
- calc_terminal/ui/theme_css.py +1396 -0
- calc_terminal/ui/thinking.py +226 -0
- calc_terminal/ui/timeline_panel.py +102 -0
- calc_terminal/ui/todo_panel.py +193 -0
- calc_terminal/ui/viewport.py +136 -0
- calc_terminal/ui/vision_panel.py +489 -0
- calc_terminal/ui/welcome_modal.py +343 -0
- calc_terminal/ui/widgets.py +160 -0
- calc_terminal/ui/workspace.py +831 -0
- calc_terminal/viewers/__init__.py +1 -0
- calc_terminal/viewers/document_viewer.py +252 -0
- calc_terminal/viewers/image_viewer.py +241 -0
- calc_terminal/viewers/pdf_viewer.py +203 -0
- calc_terminal/viewers/presentation_viewer.py +164 -0
- calc_terminal/viewers/registry.py +120 -0
- calc_terminal/viewers/spreadsheet_viewer.py +204 -0
- calc_terminal/vision/__init__.py +89 -0
- calc_terminal/vision/analysis.py +194 -0
- calc_terminal/vision/annotations.py +297 -0
- calc_terminal/vision/capture.py +171 -0
- calc_terminal/vision/context.py +231 -0
- calc_terminal/vision/correlation.py +169 -0
- calc_terminal/vision/cursor.py +258 -0
- calc_terminal/vision/events.py +66 -0
- calc_terminal/vision/frame_pipeline.py +259 -0
- calc_terminal/vision/priority.py +218 -0
- calc_terminal/vision/provider.py +180 -0
- calc_terminal/vision/safety.py +149 -0
- calc_terminal/vision/session.py +281 -0
- calc_terminal/vision/verify.py +162 -0
- calc_terminal/vision.py +514 -0
- calc_terminal/vscode_integration.py +113 -0
- calc_terminal/web/__init__.py +8 -0
- calc_terminal/web/cat_runtime.py +710 -0
- calc_terminal/web/server.py +2891 -0
- calc_terminal/web/static/css/app.css +3152 -0
- calc_terminal/web/static/icons/badge-72.png +0 -0
- calc_terminal/web/static/icons/cat.ico +0 -0
- calc_terminal/web/static/icons/icon-128.png +0 -0
- calc_terminal/web/static/icons/icon-144.png +0 -0
- calc_terminal/web/static/icons/icon-152.png +0 -0
- calc_terminal/web/static/icons/icon-192.png +0 -0
- calc_terminal/web/static/icons/icon-384.png +0 -0
- calc_terminal/web/static/icons/icon-512.png +0 -0
- calc_terminal/web/static/icons/icon-72.png +0 -0
- calc_terminal/web/static/icons/icon-96.png +0 -0
- calc_terminal/web/static/icons/icon.svg +34 -0
- calc_terminal/web/static/icons/new-project.png +0 -0
- calc_terminal/web/static/icons/open-project.png +0 -0
- calc_terminal/web/static/index.html +734 -0
- calc_terminal/web/static/js/app.js +2403 -0
- calc_terminal/web/static/manifest.json +88 -0
- calc_terminal/web/static/sw.js +230 -0
- calc_terminal/workflow_engine.py +769 -0
- calc_terminal/workspace.py +593 -0
- calc_terminal/workspace_index.py +385 -0
- cct_cli-0.7.9.0.dist-info/METADATA +210 -0
- cct_cli-0.7.9.0.dist-info/RECORD +325 -0
- cct_cli-0.7.9.0.dist-info/WHEEL +5 -0
- cct_cli-0.7.9.0.dist-info/entry_points.txt +4 -0
- cct_cli-0.7.9.0.dist-info/licenses/LICENSE +21 -0
- 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
|