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,265 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CCT first-run initialization system.
|
|
3
|
+
|
|
4
|
+
Global-install lifecycle:
|
|
5
|
+
|
|
6
|
+
cct
|
|
7
|
+
-> main() (calc_terminal.cli)
|
|
8
|
+
-> ensure_first_run() (this module)
|
|
9
|
+
-> initialize_first_run() (the one-time setup; also exposed to
|
|
10
|
+
the world as model.initialize_model()
|
|
11
|
+
in the source tree's model.py)
|
|
12
|
+
-> .initialized marker (written ONLY after success)
|
|
13
|
+
-> existing CCT startup (calc_terminal.cli._launch)
|
|
14
|
+
|
|
15
|
+
Every later `cct` launch sees the marker and skips straight to launch.
|
|
16
|
+
A failed initialization writes NO marker, so the next launch retries —
|
|
17
|
+
never silently claiming success.
|
|
18
|
+
|
|
19
|
+
Nothing here runs during `pip install`: the package installs code and
|
|
20
|
+
resources only; initialization happens inside the application lifecycle,
|
|
21
|
+
the first time the user actually runs `cct`.
|
|
22
|
+
|
|
23
|
+
Storage: a platform-aware application-data directory (never the source
|
|
24
|
+
tree, never hard-coded Windows paths). Override for testing/power users
|
|
25
|
+
with the CCT_DATA_DIR environment variable:
|
|
26
|
+
|
|
27
|
+
Windows %LOCALAPPDATA%\\CCT
|
|
28
|
+
Linux $XDG_CONFIG_HOME/cct (default ~/.config/cct)
|
|
29
|
+
macOS ~/Library/Application Support/CCT
|
|
30
|
+
|
|
31
|
+
<data dir>/
|
|
32
|
+
|-- config.json seeded defaults (never clobbers user edits)
|
|
33
|
+
|-- models.json seed copy of the packaged model metadata
|
|
34
|
+
|-- providers.json seed copy of the packaged provider registry
|
|
35
|
+
|-- cache/ model cache / runtime resources
|
|
36
|
+
|-- logs/ startup + initialization logs
|
|
37
|
+
`-- .initialized marker; created only by a SUCCESSFUL init
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
import json
|
|
41
|
+
import os
|
|
42
|
+
import sys
|
|
43
|
+
import time
|
|
44
|
+
|
|
45
|
+
_MARKER_NAME = ".initialized"
|
|
46
|
+
_MARKER_VERSION = 1
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ------------------------------------------------------------- paths ----
|
|
50
|
+
|
|
51
|
+
def data_dir():
|
|
52
|
+
"""The CCT application-data directory for this platform.
|
|
53
|
+
|
|
54
|
+
CCT_DATA_DIR (if set) wins — that's how tests simulate a clean
|
|
55
|
+
machine without touching the real profile. Otherwise the directory
|
|
56
|
+
follows each OS's convention: %LOCALAPPDATA% on Windows,
|
|
57
|
+
$XDG_CONFIG_HOME (or ~/.config) on Linux, ~/Library/Application
|
|
58
|
+
Support on macOS. All three match the CCT application-data layout
|
|
59
|
+
(config.json / models.json / providers.json / cache / logs /
|
|
60
|
+
.initialized)."""
|
|
61
|
+
override = os.environ.get("CCT_DATA_DIR", "").strip()
|
|
62
|
+
if override:
|
|
63
|
+
return os.path.abspath(override)
|
|
64
|
+
if sys.platform == "win32":
|
|
65
|
+
base = os.environ.get("LOCALAPPDATA") or os.path.join(
|
|
66
|
+
os.path.expanduser("~"), "AppData", "Local")
|
|
67
|
+
return os.path.join(base, "CCT")
|
|
68
|
+
if sys.platform == "darwin":
|
|
69
|
+
return os.path.join(
|
|
70
|
+
os.path.expanduser("~"), "Library", "Application Support", "CCT")
|
|
71
|
+
# Linux / BSD / other Unix
|
|
72
|
+
xdg = os.environ.get("XDG_CONFIG_HOME", "").strip()
|
|
73
|
+
base = xdg or os.path.join(os.path.expanduser("~"), ".config")
|
|
74
|
+
return os.path.join(base, "cct")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def initialized_path():
|
|
78
|
+
return os.path.join(data_dir(), _MARKER_NAME)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def cache_dir():
|
|
82
|
+
return os.path.join(data_dir(), "cache")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def logs_dir():
|
|
86
|
+
return os.path.join(data_dir(), "logs")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def is_initialized():
|
|
90
|
+
"""True when a successful first-run initialization has completed."""
|
|
91
|
+
return os.path.isfile(initialized_path())
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def mark_initialized():
|
|
95
|
+
"""Write the marker. Called ONLY after initialization succeeded."""
|
|
96
|
+
path = initialized_path()
|
|
97
|
+
payload = {
|
|
98
|
+
"version": _MARKER_VERSION,
|
|
99
|
+
"cct_version": _cct_version(),
|
|
100
|
+
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%S"),
|
|
101
|
+
}
|
|
102
|
+
tmp = path + ".tmp"
|
|
103
|
+
with open(tmp, "w", encoding="utf-8") as f:
|
|
104
|
+
json.dump(payload, f, indent=2)
|
|
105
|
+
os.replace(tmp, path)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _cct_version():
|
|
109
|
+
try:
|
|
110
|
+
from .app import VERSION
|
|
111
|
+
return VERSION
|
|
112
|
+
except Exception:
|
|
113
|
+
return "0.0.0"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ------------------------------------------------------------ seeding ----
|
|
117
|
+
|
|
118
|
+
def _package_resource(relpath):
|
|
119
|
+
"""Resolve a packaged resource file to an absolute path. The
|
|
120
|
+
resources live inside the calc_terminal package itself, so this
|
|
121
|
+
works identically from a source checkout and from site-packages."""
|
|
122
|
+
base = os.path.dirname(os.path.abspath(__file__))
|
|
123
|
+
return os.path.join(base, relpath)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _write_json_if_missing(path, data):
|
|
127
|
+
if os.path.exists(path):
|
|
128
|
+
return False
|
|
129
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
130
|
+
json.dump(data, f, indent=2)
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _copy_resource_if_missing(dst, src):
|
|
135
|
+
if os.path.exists(dst) or not os.path.exists(src):
|
|
136
|
+
return
|
|
137
|
+
with open(src, "r", encoding="utf-8") as r, \
|
|
138
|
+
open(dst, "w", encoding="utf-8") as w:
|
|
139
|
+
w.write(r.read())
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def seed_defaults():
|
|
143
|
+
"""Create the application-data structure and seed the reference
|
|
144
|
+
files. Existing files are never overwritten — the seeds are
|
|
145
|
+
factory defaults, user edits win."""
|
|
146
|
+
root = data_dir()
|
|
147
|
+
os.makedirs(cache_dir(), exist_ok=True)
|
|
148
|
+
os.makedirs(logs_dir(), exist_ok=True)
|
|
149
|
+
try:
|
|
150
|
+
from .config import load_config
|
|
151
|
+
_write_json_if_missing(
|
|
152
|
+
os.path.join(root, "config.json"), load_config().to_dict())
|
|
153
|
+
except Exception:
|
|
154
|
+
# config seeding is best-effort; a broken one must not fail the
|
|
155
|
+
# whole first run
|
|
156
|
+
pass
|
|
157
|
+
_copy_resource_if_missing(
|
|
158
|
+
os.path.join(root, "models.json"),
|
|
159
|
+
_package_resource(os.path.join("models", "model_metadata.json")))
|
|
160
|
+
_copy_resource_if_missing(
|
|
161
|
+
os.path.join(root, "providers.json"),
|
|
162
|
+
_package_resource(os.path.join("providers", "providers.json")))
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# ------------------------------------------------------ initialization --
|
|
166
|
+
|
|
167
|
+
def initialize_first_run():
|
|
168
|
+
"""The one-time initialization (exposed from model.py as
|
|
169
|
+
initialize_model()). Returns (ok, message).
|
|
170
|
+
|
|
171
|
+
Creates the application-data tree, seeds config/models/providers
|
|
172
|
+
reference files, and — only if every step succeeded — writes the
|
|
173
|
+
.initialized marker. Any failure returns (False, reason) with NO
|
|
174
|
+
marker, so the next `cct` launch retries."""
|
|
175
|
+
try:
|
|
176
|
+
seed_defaults()
|
|
177
|
+
mark_initialized()
|
|
178
|
+
return True, "initialization complete"
|
|
179
|
+
except OSError as e:
|
|
180
|
+
return False, f"cannot prepare application data: {e}"
|
|
181
|
+
except Exception as e:
|
|
182
|
+
return False, f"unexpected error: {type(e).__name__}: {e}"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def print_environment_card():
|
|
186
|
+
"""Print the Intelligent First-Run Diagnostic & Environment Card."""
|
|
187
|
+
import shutil
|
|
188
|
+
import platform
|
|
189
|
+
print("=" * 72)
|
|
190
|
+
print(" CAT INTELLIGENT ENVIRONMENT DETECTION")
|
|
191
|
+
print("=" * 72)
|
|
192
|
+
|
|
193
|
+
py_ver = platform.python_version()
|
|
194
|
+
os_desc = f"{platform.system()} {platform.release()} ({platform.machine()})"
|
|
195
|
+
git_installed = bool(shutil.which("git"))
|
|
196
|
+
print(f" Operating System : {os_desc}")
|
|
197
|
+
print(f" Python Runtime : {py_ver}")
|
|
198
|
+
print(f" Git Version Control: {'Installed (Available)' if git_installed else 'Missing (Optional)'}")
|
|
199
|
+
|
|
200
|
+
prof = None
|
|
201
|
+
try:
|
|
202
|
+
from .hardware_analyzer import HardwareAnalyzer
|
|
203
|
+
prof = HardwareAnalyzer.analyze()
|
|
204
|
+
print(f" CPU Compute : {prof.cpu_model} ({prof.cpu_threads} logical threads)")
|
|
205
|
+
print(f" System RAM : {prof.ram_total_gb:.1f} GB ({prof.ram_available_gb:.1f} GB available)")
|
|
206
|
+
if prof.has_gpu:
|
|
207
|
+
print(f" GPU Compute : {prof.gpu_name} ({prof.vram_gb:.1f} GB VRAM via {prof.gpu_backend})")
|
|
208
|
+
else:
|
|
209
|
+
print(" GPU Compute : CPU / Integrated Memory")
|
|
210
|
+
print(f" Local AI Tier : {prof.local_ai_tier.value}")
|
|
211
|
+
except Exception as e:
|
|
212
|
+
print(f" Hardware Detection : Basic ({e})")
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
from .ollama_download import is_ollama_running, is_ollama_installed
|
|
216
|
+
if is_ollama_running():
|
|
217
|
+
ollama_st = "Running (Active on port 11434)"
|
|
218
|
+
elif is_ollama_installed():
|
|
219
|
+
ollama_st = "Installed (Offline — will auto-launch when needed)"
|
|
220
|
+
else:
|
|
221
|
+
ollama_st = "Not Detected (Optional: install from https://ollama.com)"
|
|
222
|
+
print(f" Local Ollama Engine: {ollama_st}")
|
|
223
|
+
except Exception:
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
from .compatibility_engine import ModelCompatibilityEngine
|
|
228
|
+
from .ollama_catalog import all_models
|
|
229
|
+
engine = ModelCompatibilityEngine()
|
|
230
|
+
recs = engine.recommend_models(all_models(include_dynamic=True))
|
|
231
|
+
best_code = recs.get("best_coding", [{}])[0].get("model", {}).get("name", "qwen2.5-coder:3b")
|
|
232
|
+
best_fast = recs.get("best_fast", [{}])[0].get("model", {}).get("name", "smollm2:1.7b")
|
|
233
|
+
ram_tag = f"{prof.ram_total_gb:.0f}GB RAM" if prof else "your device"
|
|
234
|
+
print("-" * 72)
|
|
235
|
+
print(" RECOMMENDED STARTER SETUP FOR YOUR HARDWARE:")
|
|
236
|
+
print(f" * Primary Coding Model : {best_code} (Optimized for {ram_tag})")
|
|
237
|
+
print(f" * Fast Edge Autocomplete: {best_fast}")
|
|
238
|
+
print(f" * Quick Download Command : cat models install {best_code}")
|
|
239
|
+
except Exception:
|
|
240
|
+
pass
|
|
241
|
+
print("=" * 72)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def ensure_first_run():
|
|
245
|
+
"""CLI-level first-run orchestrator. Prints the startup banner and
|
|
246
|
+
runs the one-time initialization when needed. Returns an exit code
|
|
247
|
+
(0 = continue to launch, non-zero = stop with an error)."""
|
|
248
|
+
if is_initialized():
|
|
249
|
+
print("Starting CAT...")
|
|
250
|
+
return 0
|
|
251
|
+
print("CAT — Coding Agent Terminal")
|
|
252
|
+
print("Creator: Kazi Zillani")
|
|
253
|
+
print("First-time initialization...")
|
|
254
|
+
print_environment_card()
|
|
255
|
+
print("Preparing required resources...")
|
|
256
|
+
ok, msg = initialize_first_run()
|
|
257
|
+
if not ok:
|
|
258
|
+
print(f"ERROR: first-run initialization failed ({msg}).")
|
|
259
|
+
print("Nothing was marked as initialized — the next launch will retry.")
|
|
260
|
+
print(f"Application data directory: {data_dir()}")
|
|
261
|
+
return 1
|
|
262
|
+
print("Initialization complete.")
|
|
263
|
+
print()
|
|
264
|
+
print("Starting CAT...")
|
|
265
|
+
return 0
|