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,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Fallback browser via pywebview (Edge WebView2 on Windows).
|
|
3
|
+
Shows real HTML/CSS/JS, but with minimal chrome when Qt not available.
|
|
4
|
+
Still far better than terminal text — this is a real WebView2 surface.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
def launch_webview_browser(start_url: str = "about:home") -> int:
|
|
13
|
+
try:
|
|
14
|
+
import webview # type: ignore
|
|
15
|
+
except ImportError:
|
|
16
|
+
print("[CAT Browser] pywebview not installed. Run: pip install pywebview", file=sys.stderr)
|
|
17
|
+
return 2
|
|
18
|
+
|
|
19
|
+
# Normalize about:home to a data URL with new-tab HTML
|
|
20
|
+
if start_url in ("about:home", "about:blank", "", None):
|
|
21
|
+
# Load new-tab HTML via data URL
|
|
22
|
+
try:
|
|
23
|
+
from .qt_browser import _new_tab_html # reuse same HTML
|
|
24
|
+
html = _new_tab_html()
|
|
25
|
+
# pywebview can load html string via data URL
|
|
26
|
+
import urllib.parse
|
|
27
|
+
data_url = "data:text/html;charset=utf-8," + urllib.parse.quote(html)
|
|
28
|
+
start_url = data_url
|
|
29
|
+
except Exception:
|
|
30
|
+
start_url = "https://www.google.com"
|
|
31
|
+
|
|
32
|
+
# Ensure localhost URLs are correct
|
|
33
|
+
if start_url.startswith("localhost:"):
|
|
34
|
+
start_url = "http://" + start_url
|
|
35
|
+
|
|
36
|
+
title = "CAT Browser"
|
|
37
|
+
# Try to get Fomoji title if start_url is fomoji
|
|
38
|
+
if "localhost:3000" in start_url:
|
|
39
|
+
title = "CAT Browser — Fomoji"
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
# Create window with reasonable size, resizable, with min size
|
|
43
|
+
window = webview.create_window(
|
|
44
|
+
title, start_url,
|
|
45
|
+
width=1200, height=800,
|
|
46
|
+
min_size=(900, 600),
|
|
47
|
+
text_select=True,
|
|
48
|
+
)
|
|
49
|
+
# Start the GUI loop (blocks until closed)
|
|
50
|
+
# On Windows, this uses WebView2 and will render JS/WebGL correctly
|
|
51
|
+
webview.start(debug=False)
|
|
52
|
+
return 0
|
|
53
|
+
except Exception as e:
|
|
54
|
+
print(f"[CAT Browser] webview failed: {e}", file=sys.stderr)
|
|
55
|
+
# Fallback: try to open in OS default browser as last resort? But spec says no external.
|
|
56
|
+
# Instead, show error.
|
|
57
|
+
return 1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CAT Capabilities Package per §4, §56, §57:
|
|
3
|
+
Central Capability Bus, schema definitions, environment discovery, and adapters.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .schema import (
|
|
7
|
+
AvailabilityStatus,
|
|
8
|
+
Capability,
|
|
9
|
+
CapabilityCategory,
|
|
10
|
+
CapabilitySpec,
|
|
11
|
+
ExecutionError,
|
|
12
|
+
ExecutionResult,
|
|
13
|
+
)
|
|
14
|
+
from .bus import CapabilityBus, capability_bus
|
|
15
|
+
from .discovery import EnvironmentSnapshot, discover_environment
|
|
16
|
+
from .adapters import register_all_adapters
|
|
17
|
+
|
|
18
|
+
# Auto-register all built-in adapters into the singleton bus
|
|
19
|
+
if not capability_bus._initialized:
|
|
20
|
+
register_all_adapters(capability_bus)
|
|
21
|
+
capability_bus._initialized = True
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"AvailabilityStatus",
|
|
25
|
+
"CapabilityCategory",
|
|
26
|
+
"CapabilitySpec",
|
|
27
|
+
"ExecutionError",
|
|
28
|
+
"ExecutionResult",
|
|
29
|
+
"Capability",
|
|
30
|
+
"CapabilityBus",
|
|
31
|
+
"capability_bus",
|
|
32
|
+
"EnvironmentSnapshot",
|
|
33
|
+
"discover_environment",
|
|
34
|
+
"register_all_adapters",
|
|
35
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CAT Capability Adapters package.
|
|
3
|
+
Exposes concrete handlers registered into capability_bus.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .filesystem import register_filesystem_capabilities
|
|
7
|
+
from .terminal import register_terminal_capabilities
|
|
8
|
+
from .python_exec import register_python_capabilities
|
|
9
|
+
from .git_adapter import register_git_capabilities
|
|
10
|
+
from .browser_adapter import register_browser_capabilities
|
|
11
|
+
from .jupyter_adapter import register_jupyter_capabilities
|
|
12
|
+
from .ml_frameworks import register_ml_capabilities
|
|
13
|
+
from .bioinformatics import register_bio_capabilities
|
|
14
|
+
from .structural_bio import register_structural_bio_capabilities
|
|
15
|
+
from .scientific_comp import register_scientific_capabilities
|
|
16
|
+
from .platforms import register_platform_capabilities
|
|
17
|
+
from .quantum_adapter import register_quantum_capabilities
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def register_all_adapters(bus):
|
|
21
|
+
"""Register all built-in capabilities into the given CapabilityBus."""
|
|
22
|
+
register_filesystem_capabilities(bus)
|
|
23
|
+
register_terminal_capabilities(bus)
|
|
24
|
+
register_python_capabilities(bus)
|
|
25
|
+
register_git_capabilities(bus)
|
|
26
|
+
register_browser_capabilities(bus)
|
|
27
|
+
register_jupyter_capabilities(bus)
|
|
28
|
+
register_ml_capabilities(bus)
|
|
29
|
+
register_bio_capabilities(bus)
|
|
30
|
+
register_structural_bio_capabilities(bus)
|
|
31
|
+
register_scientific_capabilities(bus)
|
|
32
|
+
register_platform_capabilities(bus)
|
|
33
|
+
register_quantum_capabilities(bus)
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bioinformatics & Genomics Capability Adapter per §45:
|
|
3
|
+
- blast.search
|
|
4
|
+
- ncbi.query
|
|
5
|
+
- biopython.parse
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import shutil
|
|
12
|
+
import subprocess
|
|
13
|
+
import urllib.request
|
|
14
|
+
import urllib.parse
|
|
15
|
+
import json
|
|
16
|
+
from typing import Any, Dict, Optional, Tuple
|
|
17
|
+
|
|
18
|
+
from ..schema import (
|
|
19
|
+
AvailabilityStatus,
|
|
20
|
+
Capability,
|
|
21
|
+
CapabilityCategory,
|
|
22
|
+
CapabilitySpec,
|
|
23
|
+
ExecutionResult,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _check_bio_health() -> Tuple[AvailabilityStatus, str]:
|
|
28
|
+
has_local = shutil.which("blastn") is not None or shutil.which("blastp") is not None
|
|
29
|
+
try:
|
|
30
|
+
import Bio # noqa: F401
|
|
31
|
+
has_biopython = True
|
|
32
|
+
except ImportError:
|
|
33
|
+
has_biopython = False
|
|
34
|
+
|
|
35
|
+
if has_local or has_biopython:
|
|
36
|
+
return AvailabilityStatus.AVAILABLE, f"Bioinformatics ready (local BLAST: {has_local}, Biopython: {has_biopython})"
|
|
37
|
+
return AvailabilityStatus.AVAILABLE, "NCBI REST API available (local BLAST/Biopython not installed)"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _blast_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
41
|
+
sequence = args.get("sequence", "")
|
|
42
|
+
program = args.get("program", "blastp") # blastp, blastn
|
|
43
|
+
database = args.get("database", "nr")
|
|
44
|
+
|
|
45
|
+
if not sequence:
|
|
46
|
+
return ExecutionResult(success=False, error="sequence argument is required (FASTA or raw sequence)")
|
|
47
|
+
|
|
48
|
+
# Check for local blast tool
|
|
49
|
+
if shutil.which(program):
|
|
50
|
+
try:
|
|
51
|
+
proc = subprocess.run(
|
|
52
|
+
[program, "-db", database, "-outfmt", "0"],
|
|
53
|
+
input=sequence,
|
|
54
|
+
stdout=subprocess.PIPE,
|
|
55
|
+
stderr=subprocess.PIPE,
|
|
56
|
+
text=True,
|
|
57
|
+
timeout=60.0,
|
|
58
|
+
)
|
|
59
|
+
if proc.returncode == 0:
|
|
60
|
+
return ExecutionResult(
|
|
61
|
+
success=True,
|
|
62
|
+
output=proc.stdout,
|
|
63
|
+
metadata={"engine": "local", "program": program, "database": database},
|
|
64
|
+
)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
# Fallback to NCBI Web API
|
|
69
|
+
try:
|
|
70
|
+
url = "https://blast.ncbi.nlm.nih.gov/Blast.cgi"
|
|
71
|
+
data = urllib.parse.urlencode({
|
|
72
|
+
"CMD": "Put",
|
|
73
|
+
"PROGRAM": program,
|
|
74
|
+
"DATABASE": database,
|
|
75
|
+
"QUERY": sequence,
|
|
76
|
+
}).encode("utf-8")
|
|
77
|
+
req = urllib.request.Request(url, data=data, headers={"User-Agent": "CAT-AI-Platform/1.0"})
|
|
78
|
+
with urllib.request.urlopen(req, timeout=10.0) as resp:
|
|
79
|
+
body = resp.read().decode("utf-8", errors="replace")
|
|
80
|
+
# Extract RID (Request ID)
|
|
81
|
+
rid = ""
|
|
82
|
+
for line in body.splitlines():
|
|
83
|
+
if "RID =" in line:
|
|
84
|
+
rid = line.split("RID =")[1].strip()
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
return ExecutionResult(
|
|
88
|
+
success=True,
|
|
89
|
+
output=f"BLAST job submitted to NCBI. Request ID (RID): {rid or 'pending'}",
|
|
90
|
+
metadata={"engine": "ncbi_rest", "rid": rid, "program": program, "database": database},
|
|
91
|
+
)
|
|
92
|
+
except Exception as e:
|
|
93
|
+
return ExecutionResult(success=False, error=f"BLAST query failed: {e}")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _ncbi_query_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
97
|
+
term = args.get("term", "")
|
|
98
|
+
db = args.get("db", "protein")
|
|
99
|
+
if not term:
|
|
100
|
+
return ExecutionResult(success=False, error="term argument is required")
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db={db}&term={urllib.parse.quote_plus(term)}&retmode=json&retmax=10"
|
|
104
|
+
req = urllib.request.Request(url, headers={"User-Agent": "CAT-AI-Platform/1.0"})
|
|
105
|
+
with urllib.request.urlopen(req, timeout=8.0) as resp:
|
|
106
|
+
data = json.loads(resp.read().decode("utf-8"))
|
|
107
|
+
id_list = data.get("esearchresult", {}).get("idlist", [])
|
|
108
|
+
return ExecutionResult(
|
|
109
|
+
success=True,
|
|
110
|
+
output=id_list,
|
|
111
|
+
metadata={"db": db, "count": len(id_list), "ids": id_list},
|
|
112
|
+
)
|
|
113
|
+
except Exception as e:
|
|
114
|
+
return ExecutionResult(success=False, error=f"NCBI query failed: {e}")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _biopython_parse_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
118
|
+
file_path = args.get("path", "")
|
|
119
|
+
fmt = args.get("format", "fasta")
|
|
120
|
+
if not file_path:
|
|
121
|
+
return ExecutionResult(success=False, error="path argument is required")
|
|
122
|
+
file_path = os.path.abspath(os.path.expanduser(file_path))
|
|
123
|
+
if not os.path.exists(file_path):
|
|
124
|
+
return ExecutionResult(success=False, error=f"File not found: {file_path}")
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
from Bio import SeqIO
|
|
128
|
+
records = []
|
|
129
|
+
for rec in SeqIO.parse(file_path, fmt):
|
|
130
|
+
records.append({
|
|
131
|
+
"id": rec.id,
|
|
132
|
+
"name": rec.name,
|
|
133
|
+
"description": rec.description,
|
|
134
|
+
"length": len(rec.seq),
|
|
135
|
+
"sequence": str(rec.seq)[:100] + ("..." if len(rec.seq) > 100 else ""),
|
|
136
|
+
})
|
|
137
|
+
return ExecutionResult(success=True, output=records, metadata={"count": len(records)})
|
|
138
|
+
except ImportError:
|
|
139
|
+
# Simple fallback parser for FASTA if biopython not installed
|
|
140
|
+
if fmt.lower() == "fasta":
|
|
141
|
+
records = []
|
|
142
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
143
|
+
cur_id = ""
|
|
144
|
+
cur_seq = []
|
|
145
|
+
for line in f:
|
|
146
|
+
line = line.strip()
|
|
147
|
+
if line.startswith(">"):
|
|
148
|
+
if cur_id:
|
|
149
|
+
records.append({"id": cur_id, "length": sum(len(s) for s in cur_seq)})
|
|
150
|
+
cur_id = line[1:]
|
|
151
|
+
cur_seq = []
|
|
152
|
+
else:
|
|
153
|
+
cur_seq.append(line)
|
|
154
|
+
if cur_id:
|
|
155
|
+
records.append({"id": cur_id, "length": sum(len(s) for s in cur_seq)})
|
|
156
|
+
return ExecutionResult(success=True, output=records, metadata={"count": len(records), "parser": "fallback"})
|
|
157
|
+
return ExecutionResult(success=False, error="Biopython is required for this format (run: pip install biopython)", status=AvailabilityStatus.SOFTWARE_NOT_FOUND)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def register_bio_capabilities(bus):
|
|
161
|
+
bus.register(Capability(
|
|
162
|
+
spec=CapabilitySpec(
|
|
163
|
+
name="blast.search",
|
|
164
|
+
version="1.0.0",
|
|
165
|
+
category=CapabilityCategory.BIO,
|
|
166
|
+
description="Run BLAST sequence similarity search via local BLAST+ or NCBI REST service.",
|
|
167
|
+
input_schema={"sequence": "string", "program": "string?", "database": "string?"},
|
|
168
|
+
output_schema={"output": "string"},
|
|
169
|
+
permissions=["read_workspace"],
|
|
170
|
+
documentation="Executes nucleotide or protein sequence alignment.",
|
|
171
|
+
),
|
|
172
|
+
handler=_blast_handler,
|
|
173
|
+
health_checker=_check_bio_health,
|
|
174
|
+
))
|
|
175
|
+
|
|
176
|
+
bus.register(Capability(
|
|
177
|
+
spec=CapabilitySpec(
|
|
178
|
+
name="ncbi.query",
|
|
179
|
+
version="1.0.0",
|
|
180
|
+
category=CapabilityCategory.BIO,
|
|
181
|
+
description="Query NCBI Entrez database for proteins, nucleotides or PubMed identifiers.",
|
|
182
|
+
input_schema={"term": "string", "db": "string?"},
|
|
183
|
+
output_schema={"ids": "list"},
|
|
184
|
+
permissions=["read_workspace"],
|
|
185
|
+
documentation="Queries NCBI E-utilities.",
|
|
186
|
+
),
|
|
187
|
+
handler=_ncbi_query_handler,
|
|
188
|
+
health_checker=_check_bio_health,
|
|
189
|
+
))
|
|
190
|
+
|
|
191
|
+
bus.register(Capability(
|
|
192
|
+
spec=CapabilitySpec(
|
|
193
|
+
name="biopython.parse",
|
|
194
|
+
version="1.0.0",
|
|
195
|
+
category=CapabilityCategory.BIO,
|
|
196
|
+
description="Parse biological sequence files (FASTA, GenBank, PDB).",
|
|
197
|
+
input_schema={"path": "string", "format": "string?"},
|
|
198
|
+
output_schema={"records": "list"},
|
|
199
|
+
permissions=["read_workspace"],
|
|
200
|
+
documentation="Extracts biological sequence records from files.",
|
|
201
|
+
),
|
|
202
|
+
handler=_biopython_parse_handler,
|
|
203
|
+
health_checker=_check_bio_health,
|
|
204
|
+
))
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Browser Capabilities Adapter per §68:
|
|
3
|
+
- browser.navigate
|
|
4
|
+
- browser.click
|
|
5
|
+
- browser.type
|
|
6
|
+
- browser.screenshot
|
|
7
|
+
- browser.inspect
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
from typing import Any, Dict, Optional, Tuple
|
|
14
|
+
|
|
15
|
+
from ..schema import (
|
|
16
|
+
AvailabilityStatus,
|
|
17
|
+
Capability,
|
|
18
|
+
CapabilityCategory,
|
|
19
|
+
CapabilitySpec,
|
|
20
|
+
ExecutionResult,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _check_browser_health() -> Tuple[AvailabilityStatus, str]:
|
|
25
|
+
try:
|
|
26
|
+
from ...browser.engine import PLAYWRIGHT_AVAILABLE
|
|
27
|
+
if PLAYWRIGHT_AVAILABLE:
|
|
28
|
+
return AvailabilityStatus.AVAILABLE, "Playwright Chromium engine available"
|
|
29
|
+
return AvailabilityStatus.SOFTWARE_NOT_FOUND, "playwright package not installed (run: pip install playwright && playwright install chromium)"
|
|
30
|
+
except Exception as e:
|
|
31
|
+
return AvailabilityStatus.UNAVAILABLE, str(e)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _navigate_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
35
|
+
url = args.get("url", "")
|
|
36
|
+
if not url:
|
|
37
|
+
return ExecutionResult(success=False, error="url argument is required")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
from ...browser.preview import PreviewController
|
|
41
|
+
ctrl = PreviewController.instance() if hasattr(PreviewController, "instance") else None
|
|
42
|
+
if ctrl and ctrl.running:
|
|
43
|
+
res = ctrl.navigate(url)
|
|
44
|
+
return ExecutionResult(success=True, output=f"Navigated to {url}", metadata={"url": url})
|
|
45
|
+
# If preview controller not actively running, check standalone Playwright
|
|
46
|
+
from ...browser.engine import BrowserEngine
|
|
47
|
+
engine = BrowserEngine(headless=True)
|
|
48
|
+
engine.start()
|
|
49
|
+
snap = engine.navigate(url)
|
|
50
|
+
engine.stop()
|
|
51
|
+
return ExecutionResult(
|
|
52
|
+
success=True,
|
|
53
|
+
output=f"Successfully loaded {snap.url} (HTTP {snap.status_code}) - Title: '{snap.title}'",
|
|
54
|
+
metadata={"title": snap.title, "url": snap.url, "status_code": snap.status_code},
|
|
55
|
+
)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
return ExecutionResult(success=False, error=f"Navigation failed: {e}")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _click_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
61
|
+
target = args.get("target") or args.get("selector", "")
|
|
62
|
+
if not target:
|
|
63
|
+
return ExecutionResult(success=False, error="target or selector argument is required")
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
from ...browser.preview import PreviewController
|
|
67
|
+
ctrl = PreviewController.instance() if hasattr(PreviewController, "instance") else None
|
|
68
|
+
if ctrl and ctrl.engine and ctrl.engine.available:
|
|
69
|
+
ok = ctrl.engine.click(target)
|
|
70
|
+
return ExecutionResult(success=ok, output=f"Clicked element '{target}'" if ok else f"Could not find element '{target}'")
|
|
71
|
+
return ExecutionResult(success=False, error="Browser engine is not currently running")
|
|
72
|
+
except Exception as e:
|
|
73
|
+
return ExecutionResult(success=False, error=f"Browser click failed: {e}")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _type_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
77
|
+
target = args.get("target") or args.get("selector", "")
|
|
78
|
+
text = args.get("text", "")
|
|
79
|
+
if not target:
|
|
80
|
+
return ExecutionResult(success=False, error="target argument is required")
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
from ...browser.preview import PreviewController
|
|
84
|
+
ctrl = PreviewController.instance() if hasattr(PreviewController, "instance") else None
|
|
85
|
+
if ctrl and ctrl.engine and ctrl.engine.available:
|
|
86
|
+
ok = ctrl.engine.type_text(target, text)
|
|
87
|
+
return ExecutionResult(success=ok, output=f"Typed text into '{target}'" if ok else f"Could not type into '{target}'")
|
|
88
|
+
return ExecutionResult(success=False, error="Browser engine is not currently running")
|
|
89
|
+
except Exception as e:
|
|
90
|
+
return ExecutionResult(success=False, error=f"Browser type failed: {e}")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _screenshot_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
94
|
+
dest = args.get("destination", "screenshot.png")
|
|
95
|
+
dest = os.path.abspath(os.path.expanduser(dest))
|
|
96
|
+
try:
|
|
97
|
+
from ...browser.preview import PreviewController
|
|
98
|
+
ctrl = PreviewController.instance() if hasattr(PreviewController, "instance") else None
|
|
99
|
+
if ctrl and ctrl.engine and ctrl.engine.available:
|
|
100
|
+
snap_path = ctrl.engine.screenshot(dest)
|
|
101
|
+
return ExecutionResult(success=True, output=f"Screenshot saved to {dest}", metadata={"path": dest})
|
|
102
|
+
return ExecutionResult(success=False, error="Browser engine is not running to take screenshot")
|
|
103
|
+
except Exception as e:
|
|
104
|
+
return ExecutionResult(success=False, error=f"Screenshot failed: {e}")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _inspect_handler(args: Dict[str, Any], context: Optional[Dict[str, Any]] = None) -> ExecutionResult:
|
|
108
|
+
try:
|
|
109
|
+
from ...browser.preview import PreviewController
|
|
110
|
+
ctrl = PreviewController.instance() if hasattr(PreviewController, "instance") else None
|
|
111
|
+
if ctrl and ctrl.engine and ctrl.engine.available:
|
|
112
|
+
snap = ctrl.engine.snapshot()
|
|
113
|
+
return ExecutionResult(
|
|
114
|
+
success=True,
|
|
115
|
+
output={
|
|
116
|
+
"title": snap.title,
|
|
117
|
+
"url": snap.url,
|
|
118
|
+
"status_code": snap.status_code,
|
|
119
|
+
"headings": snap.headings,
|
|
120
|
+
"links_count": len(snap.links),
|
|
121
|
+
"buttons_count": len(snap.buttons),
|
|
122
|
+
"console_errors": snap.js_errors,
|
|
123
|
+
},
|
|
124
|
+
metadata={"title": snap.title, "url": snap.url},
|
|
125
|
+
)
|
|
126
|
+
return ExecutionResult(success=False, error="Browser engine is not currently running")
|
|
127
|
+
except Exception as e:
|
|
128
|
+
return ExecutionResult(success=False, error=f"Inspect failed: {e}")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def register_browser_capabilities(bus):
|
|
132
|
+
bus.register(Capability(
|
|
133
|
+
spec=CapabilitySpec(
|
|
134
|
+
name="browser.navigate",
|
|
135
|
+
version="1.0.0",
|
|
136
|
+
category=CapabilityCategory.BROWSER,
|
|
137
|
+
description="Navigate to a URL using the real embedded Chromium engine.",
|
|
138
|
+
input_schema={"url": "string"},
|
|
139
|
+
output_schema={"output": "string"},
|
|
140
|
+
permissions=["browser_automation"],
|
|
141
|
+
documentation="Loads a webpage in Chromium and waits for network idle.",
|
|
142
|
+
),
|
|
143
|
+
handler=_navigate_handler,
|
|
144
|
+
health_checker=_check_browser_health,
|
|
145
|
+
))
|
|
146
|
+
|
|
147
|
+
bus.register(Capability(
|
|
148
|
+
spec=CapabilitySpec(
|
|
149
|
+
name="browser.click",
|
|
150
|
+
version="1.0.0",
|
|
151
|
+
category=CapabilityCategory.BROWSER,
|
|
152
|
+
description="Click on an interactive element by selector or visible text.",
|
|
153
|
+
input_schema={"target": "string"},
|
|
154
|
+
output_schema={"output": "string"},
|
|
155
|
+
permissions=["browser_automation"],
|
|
156
|
+
documentation="Clicks an element in the active browser page.",
|
|
157
|
+
),
|
|
158
|
+
handler=_click_handler,
|
|
159
|
+
health_checker=_check_browser_health,
|
|
160
|
+
))
|
|
161
|
+
|
|
162
|
+
bus.register(Capability(
|
|
163
|
+
spec=CapabilitySpec(
|
|
164
|
+
name="browser.type",
|
|
165
|
+
version="1.0.0",
|
|
166
|
+
category=CapabilityCategory.BROWSER,
|
|
167
|
+
description="Type text into an input field in the active browser page.",
|
|
168
|
+
input_schema={"target": "string", "text": "string"},
|
|
169
|
+
output_schema={"output": "string"},
|
|
170
|
+
permissions=["browser_automation"],
|
|
171
|
+
documentation="Focuses and types into an input/textarea.",
|
|
172
|
+
),
|
|
173
|
+
handler=_type_handler,
|
|
174
|
+
health_checker=_check_browser_health,
|
|
175
|
+
))
|
|
176
|
+
|
|
177
|
+
bus.register(Capability(
|
|
178
|
+
spec=CapabilitySpec(
|
|
179
|
+
name="browser.screenshot",
|
|
180
|
+
version="1.0.0",
|
|
181
|
+
category=CapabilityCategory.BROWSER,
|
|
182
|
+
description="Capture a screenshot of the current browser page to disk.",
|
|
183
|
+
input_schema={"destination": "string?"},
|
|
184
|
+
output_schema={"output": "string"},
|
|
185
|
+
permissions=["browser_automation"],
|
|
186
|
+
documentation="Saves a PNG screenshot of the viewport.",
|
|
187
|
+
),
|
|
188
|
+
handler=_screenshot_handler,
|
|
189
|
+
health_checker=_check_browser_health,
|
|
190
|
+
))
|
|
191
|
+
|
|
192
|
+
bus.register(Capability(
|
|
193
|
+
spec=CapabilitySpec(
|
|
194
|
+
name="browser.inspect",
|
|
195
|
+
version="1.0.0",
|
|
196
|
+
category=CapabilityCategory.BROWSER,
|
|
197
|
+
description="Inspect the current page DOM structure, interactive elements, and console errors.",
|
|
198
|
+
input_schema={},
|
|
199
|
+
output_schema={"output": "object"},
|
|
200
|
+
permissions=["browser_automation"],
|
|
201
|
+
documentation="Extracts headings, links, buttons, and console output.",
|
|
202
|
+
),
|
|
203
|
+
handler=_inspect_handler,
|
|
204
|
+
health_checker=_check_browser_health,
|
|
205
|
+
))
|