glaip-sdk 0.1.2__py3-none-any.whl ā 0.7.17__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.
- glaip_sdk/__init__.py +44 -4
- glaip_sdk/_version.py +9 -0
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1413 -0
- glaip_sdk/branding.py +126 -2
- glaip_sdk/cli/account_store.py +555 -0
- glaip_sdk/cli/auth.py +260 -15
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents/__init__.py +116 -0
- glaip_sdk/cli/commands/agents/_common.py +562 -0
- glaip_sdk/cli/commands/agents/create.py +155 -0
- glaip_sdk/cli/commands/agents/delete.py +64 -0
- glaip_sdk/cli/commands/agents/get.py +89 -0
- glaip_sdk/cli/commands/agents/list.py +129 -0
- glaip_sdk/cli/commands/agents/run.py +264 -0
- glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
- glaip_sdk/cli/commands/agents/update.py +112 -0
- glaip_sdk/cli/commands/common_config.py +104 -0
- glaip_sdk/cli/commands/configure.py +728 -113
- glaip_sdk/cli/commands/mcps/__init__.py +94 -0
- glaip_sdk/cli/commands/mcps/_common.py +459 -0
- glaip_sdk/cli/commands/mcps/connect.py +82 -0
- glaip_sdk/cli/commands/mcps/create.py +152 -0
- glaip_sdk/cli/commands/mcps/delete.py +73 -0
- glaip_sdk/cli/commands/mcps/get.py +212 -0
- glaip_sdk/cli/commands/mcps/list.py +69 -0
- glaip_sdk/cli/commands/mcps/tools.py +235 -0
- glaip_sdk/cli/commands/mcps/update.py +190 -0
- glaip_sdk/cli/commands/models.py +12 -8
- glaip_sdk/cli/commands/shared/__init__.py +21 -0
- glaip_sdk/cli/commands/shared/formatters.py +91 -0
- glaip_sdk/cli/commands/tools/__init__.py +69 -0
- glaip_sdk/cli/commands/tools/_common.py +80 -0
- glaip_sdk/cli/commands/tools/create.py +228 -0
- glaip_sdk/cli/commands/tools/delete.py +61 -0
- glaip_sdk/cli/commands/tools/get.py +103 -0
- glaip_sdk/cli/commands/tools/list.py +69 -0
- glaip_sdk/cli/commands/tools/script.py +49 -0
- glaip_sdk/cli/commands/tools/update.py +102 -0
- glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
- glaip_sdk/cli/commands/transcripts/_common.py +9 -0
- glaip_sdk/cli/commands/transcripts/clear.py +5 -0
- glaip_sdk/cli/commands/transcripts/detail.py +5 -0
- glaip_sdk/cli/commands/transcripts_original.py +756 -0
- glaip_sdk/cli/commands/update.py +163 -17
- glaip_sdk/cli/config.py +49 -4
- glaip_sdk/cli/constants.py +38 -0
- glaip_sdk/cli/context.py +8 -0
- glaip_sdk/cli/core/__init__.py +79 -0
- glaip_sdk/cli/core/context.py +124 -0
- glaip_sdk/cli/core/output.py +851 -0
- glaip_sdk/cli/core/prompting.py +649 -0
- glaip_sdk/cli/core/rendering.py +187 -0
- glaip_sdk/cli/display.py +41 -20
- glaip_sdk/cli/entrypoint.py +20 -0
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +6 -3
- glaip_sdk/cli/main.py +340 -143
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/pager.py +12 -13
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/resolution.py +2 -1
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/accounts_controller.py +580 -0
- glaip_sdk/cli/slash/accounts_shared.py +75 -0
- glaip_sdk/cli/slash/agent_session.py +62 -21
- glaip_sdk/cli/slash/prompt.py +21 -0
- glaip_sdk/cli/slash/remote_runs_controller.py +568 -0
- glaip_sdk/cli/slash/session.py +1105 -153
- glaip_sdk/cli/slash/tui/__init__.py +36 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +177 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +1853 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/clipboard.py +195 -0
- glaip_sdk/cli/slash/tui/context.py +92 -0
- glaip_sdk/cli/slash/tui/indicators.py +341 -0
- glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
- glaip_sdk/cli/slash/tui/layouts/__init__.py +14 -0
- glaip_sdk/cli/slash/tui/layouts/harlequin.py +184 -0
- glaip_sdk/cli/slash/tui/loading.py +80 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +760 -0
- glaip_sdk/cli/slash/tui/terminal.py +407 -0
- glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
- glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
- glaip_sdk/cli/slash/tui/theme/manager.py +112 -0
- glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
- glaip_sdk/cli/slash/tui/toast.py +388 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +255 -44
- glaip_sdk/cli/transcript/capture.py +66 -1
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/viewer.py +72 -463
- glaip_sdk/cli/tui_settings.py +125 -0
- glaip_sdk/cli/update_notifier.py +227 -10
- glaip_sdk/cli/validators.py +5 -6
- glaip_sdk/client/__init__.py +3 -1
- glaip_sdk/client/_schedule_payloads.py +89 -0
- glaip_sdk/client/agent_runs.py +147 -0
- glaip_sdk/client/agents.py +576 -44
- glaip_sdk/client/base.py +26 -0
- glaip_sdk/client/hitl.py +136 -0
- glaip_sdk/client/main.py +25 -14
- glaip_sdk/client/mcps.py +165 -24
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/{_agent_payloads.py ā payloads/agent/requests.py} +63 -47
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/run_rendering.py +546 -92
- glaip_sdk/client/schedules.py +439 -0
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +206 -32
- glaip_sdk/config/constants.py +33 -2
- glaip_sdk/guardrails/__init__.py +80 -0
- glaip_sdk/guardrails/serializer.py +89 -0
- glaip_sdk/hitl/__init__.py +48 -0
- glaip_sdk/hitl/base.py +64 -0
- glaip_sdk/hitl/callback.py +43 -0
- glaip_sdk/hitl/local.py +121 -0
- glaip_sdk/hitl/remote.py +523 -0
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +136 -0
- glaip_sdk/models/_provider_mappings.py +101 -0
- glaip_sdk/models/_validation.py +97 -0
- glaip_sdk/models/agent.py +48 -0
- glaip_sdk/models/agent_runs.py +117 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/constants.py +141 -0
- glaip_sdk/models/mcp.py +33 -0
- glaip_sdk/models/model.py +170 -0
- glaip_sdk/models/schedule.py +224 -0
- glaip_sdk/models/tool.py +33 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/payload_schemas/agent.py +1 -0
- glaip_sdk/payload_schemas/guardrails.py +34 -0
- glaip_sdk/registry/__init__.py +55 -0
- glaip_sdk/registry/agent.py +164 -0
- glaip_sdk/registry/base.py +139 -0
- glaip_sdk/registry/mcp.py +253 -0
- glaip_sdk/registry/tool.py +445 -0
- glaip_sdk/rich_components.py +58 -2
- glaip_sdk/runner/__init__.py +76 -0
- glaip_sdk/runner/base.py +84 -0
- glaip_sdk/runner/deps.py +115 -0
- glaip_sdk/runner/langgraph.py +1055 -0
- glaip_sdk/runner/logging_config.py +77 -0
- glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +116 -0
- glaip_sdk/runner/tool_adapter/__init__.py +18 -0
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +242 -0
- glaip_sdk/schedules/__init__.py +22 -0
- glaip_sdk/schedules/base.py +291 -0
- glaip_sdk/tools/__init__.py +22 -0
- glaip_sdk/tools/base.py +488 -0
- glaip_sdk/utils/__init__.py +59 -12
- glaip_sdk/utils/a2a/__init__.py +34 -0
- glaip_sdk/utils/a2a/event_processor.py +188 -0
- glaip_sdk/utils/agent_config.py +8 -2
- glaip_sdk/utils/bundler.py +403 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +39 -7
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +23 -15
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +0 -33
- glaip_sdk/utils/import_export.py +12 -7
- glaip_sdk/utils/import_resolver.py +524 -0
- glaip_sdk/utils/instructions.py +101 -0
- glaip_sdk/utils/rendering/__init__.py +115 -1
- glaip_sdk/utils/rendering/formatting.py +5 -30
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer ā layout}/panels.py +9 -0
- glaip_sdk/utils/rendering/{renderer ā layout}/progress.py +70 -1
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +1 -0
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -47
- glaip_sdk/utils/rendering/renderer/base.py +299 -1434
- glaip_sdk/utils/rendering/renderer/config.py +1 -5
- glaip_sdk/utils/rendering/renderer/debug.py +26 -20
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +4 -33
- glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
- glaip_sdk/utils/rendering/state.py +204 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/{steps.py ā steps/event_processor.py} +53 -440
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/steps/manager.py +387 -0
- glaip_sdk/utils/rendering/timing.py +36 -0
- glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
- glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
- glaip_sdk/utils/resource_refs.py +25 -13
- glaip_sdk/utils/runtime_config.py +426 -0
- glaip_sdk/utils/serialization.py +18 -0
- glaip_sdk/utils/sync.py +162 -0
- glaip_sdk/utils/tool_detection.py +301 -0
- glaip_sdk/utils/tool_storage_provider.py +140 -0
- glaip_sdk/utils/validation.py +16 -24
- {glaip_sdk-0.1.2.dist-info ā glaip_sdk-0.7.17.dist-info}/METADATA +69 -23
- glaip_sdk-0.7.17.dist-info/RECORD +224 -0
- {glaip_sdk-0.1.2.dist-info ā glaip_sdk-0.7.17.dist-info}/WHEEL +2 -1
- glaip_sdk-0.7.17.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.7.17.dist-info/top_level.txt +1 -0
- glaip_sdk/cli/commands/agents.py +0 -1369
- glaip_sdk/cli/commands/mcps.py +0 -1187
- glaip_sdk/cli/commands/tools.py +0 -584
- glaip_sdk/cli/utils.py +0 -1278
- glaip_sdk/models.py +0 -240
- glaip_sdk-0.1.2.dist-info/RECORD +0 -82
- glaip_sdk-0.1.2.dist-info/entry_points.txt +0 -3
glaip_sdk/cli/main.py
CHANGED
|
@@ -4,16 +4,13 @@ Authors:
|
|
|
4
4
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import logging
|
|
8
8
|
import subprocess
|
|
9
9
|
import sys
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
12
|
import click
|
|
13
13
|
from rich.console import Console
|
|
14
|
-
|
|
15
|
-
from glaip_sdk import Client
|
|
16
|
-
from glaip_sdk._version import __version__ as _SDK_VERSION
|
|
17
14
|
from glaip_sdk.branding import (
|
|
18
15
|
ERROR,
|
|
19
16
|
ERROR_STYLE,
|
|
@@ -26,6 +23,9 @@ from glaip_sdk.branding import (
|
|
|
26
23
|
WARNING_STYLE,
|
|
27
24
|
AIPBranding,
|
|
28
25
|
)
|
|
26
|
+
from glaip_sdk.cli.account_store import get_account_store
|
|
27
|
+
from glaip_sdk.cli.auth import resolve_credentials
|
|
28
|
+
from glaip_sdk.cli.commands.accounts import accounts_group
|
|
29
29
|
from glaip_sdk.cli.commands.agents import agents_group
|
|
30
30
|
from glaip_sdk.cli.commands.configure import (
|
|
31
31
|
config_group,
|
|
@@ -34,17 +34,66 @@ from glaip_sdk.cli.commands.configure import (
|
|
|
34
34
|
from glaip_sdk.cli.commands.mcps import mcps_group
|
|
35
35
|
from glaip_sdk.cli.commands.models import models_group
|
|
36
36
|
from glaip_sdk.cli.commands.tools import tools_group
|
|
37
|
-
from glaip_sdk.cli.commands.
|
|
37
|
+
from glaip_sdk.cli.commands.transcripts import transcripts_group
|
|
38
|
+
from glaip_sdk.cli.commands.update import (
|
|
39
|
+
_build_missing_pip_guidance,
|
|
40
|
+
_build_manual_upgrade_command,
|
|
41
|
+
_build_upgrade_command,
|
|
42
|
+
_is_pip_available,
|
|
43
|
+
_is_uv_managed_environment,
|
|
44
|
+
update_command,
|
|
45
|
+
)
|
|
38
46
|
from glaip_sdk.cli.config import load_config
|
|
47
|
+
from glaip_sdk.cli.hints import in_slash_mode
|
|
48
|
+
from glaip_sdk.cli.core.output import format_size, sdk_version
|
|
49
|
+
from glaip_sdk.cli.core.rendering import spinner_context, update_spinner
|
|
39
50
|
from glaip_sdk.cli.transcript import get_transcript_cache_stats
|
|
40
51
|
from glaip_sdk.cli.update_notifier import maybe_notify_update
|
|
41
|
-
from glaip_sdk.cli.utils import in_slash_mode, spinner_context, update_spinner
|
|
42
52
|
from glaip_sdk.config.constants import (
|
|
43
53
|
DEFAULT_AGENT_RUN_TIMEOUT,
|
|
44
54
|
)
|
|
45
55
|
from glaip_sdk.icons import ICON_AGENT
|
|
46
56
|
from glaip_sdk.rich_components import AIPPanel, AIPTable
|
|
47
57
|
|
|
58
|
+
# Constants
|
|
59
|
+
UPDATE_ERROR_TITLE = "ā Update Error"
|
|
60
|
+
|
|
61
|
+
Client: type[Any] | None = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _resolve_client_class() -> type[Any]:
|
|
65
|
+
"""Resolve the Client class lazily to avoid heavy imports at CLI startup."""
|
|
66
|
+
global Client
|
|
67
|
+
if Client is None:
|
|
68
|
+
from glaip_sdk import Client as ClientClass # noqa: PLC0415
|
|
69
|
+
|
|
70
|
+
Client = ClientClass
|
|
71
|
+
return Client
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _suppress_chatty_loggers() -> None:
|
|
75
|
+
"""Silence noisy SDK/httpx logs for CLI output."""
|
|
76
|
+
# Ensure CLI logging is configured (idempotent)
|
|
77
|
+
from glaip_sdk.runner.logging_config import setup_cli_logging # noqa: PLC0415
|
|
78
|
+
|
|
79
|
+
setup_cli_logging()
|
|
80
|
+
|
|
81
|
+
# Also suppress SDK-specific loggers
|
|
82
|
+
noisy_loggers = [
|
|
83
|
+
"glaip_sdk.client",
|
|
84
|
+
"httpx",
|
|
85
|
+
"httpcore",
|
|
86
|
+
]
|
|
87
|
+
for name in noisy_loggers:
|
|
88
|
+
logger = logging.getLogger(name)
|
|
89
|
+
# Respect existing configuration: only raise level when unset,
|
|
90
|
+
# and avoid changing propagation if a custom handler is already attached.
|
|
91
|
+
if logger.level == logging.NOTSET:
|
|
92
|
+
logger.setLevel(logging.WARNING)
|
|
93
|
+
if not logger.handlers:
|
|
94
|
+
logger.propagate = False
|
|
95
|
+
|
|
96
|
+
|
|
48
97
|
# Import SlashSession for potential mocking in tests
|
|
49
98
|
try:
|
|
50
99
|
from glaip_sdk.cli.slash import SlashSession
|
|
@@ -56,35 +105,17 @@ except ImportError: # pragma: no cover - optional slash dependencies
|
|
|
56
105
|
AVAILABLE_STATUS = "ā
Available"
|
|
57
106
|
|
|
58
107
|
|
|
59
|
-
def _format_size(num: int) -> str:
|
|
60
|
-
"""Return a human-readable byte size."""
|
|
61
|
-
if num <= 0:
|
|
62
|
-
return "0B"
|
|
63
|
-
|
|
64
|
-
units = ["B", "KB", "MB", "GB", "TB"]
|
|
65
|
-
value = float(num)
|
|
66
|
-
for unit in units:
|
|
67
|
-
if value < 1024 or unit == units[-1]:
|
|
68
|
-
if value >= 100 or unit == "B":
|
|
69
|
-
return f"{value:.0f}{unit}"
|
|
70
|
-
if value >= 10:
|
|
71
|
-
return f"{value:.1f}{unit}"
|
|
72
|
-
return f"{value:.2f}{unit}"
|
|
73
|
-
value /= 1024
|
|
74
|
-
return f"{value:.1f}TB" # pragma: no cover - defensive fallback
|
|
75
|
-
|
|
76
|
-
|
|
77
108
|
@click.group(invoke_without_command=True)
|
|
78
|
-
@click.version_option(
|
|
109
|
+
@click.version_option(package_name="glaip-sdk", prog_name="aip")
|
|
79
110
|
@click.option(
|
|
80
111
|
"--api-url",
|
|
81
|
-
|
|
82
|
-
|
|
112
|
+
help="(Deprecated) AIP API URL; use profiles via --account instead",
|
|
113
|
+
hidden=True,
|
|
83
114
|
)
|
|
84
115
|
@click.option(
|
|
85
116
|
"--api-key",
|
|
86
|
-
|
|
87
|
-
|
|
117
|
+
help="(Deprecated) AIP API Key; use profiles via --account instead",
|
|
118
|
+
hidden=True,
|
|
88
119
|
)
|
|
89
120
|
@click.option("--timeout", default=30.0, help="Request timeout in seconds")
|
|
90
121
|
@click.option(
|
|
@@ -95,6 +126,12 @@ def _format_size(num: int) -> str:
|
|
|
95
126
|
help="Output view format",
|
|
96
127
|
)
|
|
97
128
|
@click.option("--no-tty", is_flag=True, help="Disable TTY renderer")
|
|
129
|
+
@click.option(
|
|
130
|
+
"--account",
|
|
131
|
+
"account_name",
|
|
132
|
+
help="Target a named account profile for this command",
|
|
133
|
+
hidden=True, # Hidden by default, shown with --help --all
|
|
134
|
+
)
|
|
98
135
|
@click.pass_context
|
|
99
136
|
def main(
|
|
100
137
|
ctx: Any,
|
|
@@ -103,6 +140,7 @@ def main(
|
|
|
103
140
|
timeout: float | None,
|
|
104
141
|
view: str | None,
|
|
105
142
|
no_tty: bool,
|
|
143
|
+
account_name: str | None,
|
|
106
144
|
) -> None:
|
|
107
145
|
r"""GL AIP SDK Command Line Interface.
|
|
108
146
|
|
|
@@ -113,9 +151,14 @@ def main(
|
|
|
113
151
|
Examples:
|
|
114
152
|
aip version # Show detailed version info
|
|
115
153
|
aip configure # Configure credentials
|
|
154
|
+
aip accounts add prod # Add account profile
|
|
155
|
+
aip accounts use staging # Switch account
|
|
116
156
|
aip agents list # List all agents
|
|
117
157
|
aip tools create my_tool.py # Create a new tool
|
|
118
158
|
aip agents run my-agent "Hello world" # Run an agent
|
|
159
|
+
|
|
160
|
+
\b
|
|
161
|
+
NEW: Store multiple accounts via 'aip accounts add' and switch with 'aip accounts use'.
|
|
119
162
|
"""
|
|
120
163
|
# Store configuration in context
|
|
121
164
|
ctx.ensure_object(dict)
|
|
@@ -123,6 +166,9 @@ def main(
|
|
|
123
166
|
ctx.obj["api_key"] = api_key
|
|
124
167
|
ctx.obj["timeout"] = timeout
|
|
125
168
|
ctx.obj["view"] = view
|
|
169
|
+
ctx.obj["account_name"] = account_name
|
|
170
|
+
|
|
171
|
+
_suppress_chatty_loggers()
|
|
126
172
|
|
|
127
173
|
ctx.obj["tty"] = not no_tty
|
|
128
174
|
|
|
@@ -135,12 +181,13 @@ def main(
|
|
|
135
181
|
|
|
136
182
|
if not ctx.resilient_parsing and ctx.obj["tty"] and not launching_slash:
|
|
137
183
|
console = Console()
|
|
138
|
-
maybe_notify_update(
|
|
139
|
-
|
|
184
|
+
preferred_console = maybe_notify_update(
|
|
185
|
+
sdk_version(),
|
|
140
186
|
console=console,
|
|
141
187
|
ctx=ctx,
|
|
142
188
|
slash_command="update",
|
|
143
189
|
)
|
|
190
|
+
ctx.obj["_preferred_console"] = preferred_console or console
|
|
144
191
|
|
|
145
192
|
if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
|
|
146
193
|
if launching_slash:
|
|
@@ -153,11 +200,13 @@ def main(
|
|
|
153
200
|
|
|
154
201
|
|
|
155
202
|
# Add command groups
|
|
203
|
+
main.add_command(accounts_group)
|
|
156
204
|
main.add_command(agents_group)
|
|
157
205
|
main.add_command(config_group)
|
|
158
206
|
main.add_command(tools_group)
|
|
159
207
|
main.add_command(mcps_group)
|
|
160
208
|
main.add_command(models_group)
|
|
209
|
+
main.add_command(transcripts_group)
|
|
161
210
|
|
|
162
211
|
# Add top-level commands
|
|
163
212
|
main.add_command(configure_command)
|
|
@@ -181,59 +230,113 @@ def _should_launch_slash(ctx: click.Context) -> bool:
|
|
|
181
230
|
|
|
182
231
|
def _load_and_merge_config(ctx: click.Context) -> dict:
|
|
183
232
|
"""Load configuration from multiple sources and merge them."""
|
|
184
|
-
# Load config from file and merge with context
|
|
185
|
-
file_config = load_config()
|
|
186
233
|
context_config = ctx.obj or {}
|
|
234
|
+
account_name = context_config.get("account_name")
|
|
187
235
|
|
|
188
|
-
#
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
236
|
+
# Resolve credentials using new account store system
|
|
237
|
+
api_url, api_key, source = resolve_credentials(
|
|
238
|
+
account_name=account_name,
|
|
239
|
+
api_url=context_config.get("api_url"),
|
|
240
|
+
api_key=context_config.get("api_key"),
|
|
241
|
+
)
|
|
194
242
|
|
|
195
|
-
#
|
|
196
|
-
|
|
243
|
+
# Load other config values (timeout, etc.) from legacy config
|
|
244
|
+
legacy_config = load_config()
|
|
245
|
+
timeout = context_config.get("timeout") or legacy_config.get("timeout")
|
|
197
246
|
|
|
198
|
-
|
|
199
|
-
|
|
247
|
+
return {
|
|
248
|
+
"api_url": api_url,
|
|
249
|
+
"api_key": api_key,
|
|
250
|
+
"timeout": timeout,
|
|
251
|
+
"_source": source, # Track where credentials came from
|
|
252
|
+
}
|
|
200
253
|
|
|
201
254
|
|
|
202
255
|
def _validate_config_and_show_error(config: dict, console: Console) -> None:
|
|
203
256
|
"""Validate configuration and show error if incomplete."""
|
|
204
|
-
if
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
257
|
+
if config.get("api_url") and config.get("api_key"):
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
# Best effort: avoid failing validation due to config I/O issues.
|
|
261
|
+
has_accounts = True
|
|
262
|
+
logger = logging.getLogger(__name__)
|
|
263
|
+
try:
|
|
264
|
+
store = get_account_store()
|
|
265
|
+
try:
|
|
266
|
+
has_accounts = bool(store.list_accounts())
|
|
267
|
+
except Exception:
|
|
268
|
+
logger.warning("Failed to list accounts from account store.", exc_info=True)
|
|
269
|
+
has_accounts = True
|
|
270
|
+
except Exception:
|
|
271
|
+
logger.warning("Failed to initialize account store.", exc_info=True)
|
|
272
|
+
has_accounts = True
|
|
273
|
+
|
|
274
|
+
no_accounts_hint = "" if has_accounts else "\n ⢠No accounts found; create one now to continue"
|
|
275
|
+
console.print(
|
|
276
|
+
AIPPanel(
|
|
277
|
+
f"[{ERROR_STYLE}]ā Configuration incomplete[/]\n\n"
|
|
278
|
+
f"š Current config:\n"
|
|
279
|
+
f" ⢠API URL: {config.get('api_url', 'Not set')}\n"
|
|
280
|
+
f" ⢠API Key: {'***' + config.get('api_key', '')[-4:] if config.get('api_key') else 'Not set'}\n\n"
|
|
281
|
+
f"š” To fix this:\n"
|
|
282
|
+
f" ⢠Run 'aip accounts add default' to set up credentials\n"
|
|
283
|
+
f" ⢠Or run 'aip configure' for interactive setup\n"
|
|
284
|
+
f" ⢠Or run 'aip accounts list' to see current accounts{no_accounts_hint}",
|
|
285
|
+
title="ā Configuration Error",
|
|
286
|
+
border_style=ERROR,
|
|
287
|
+
),
|
|
288
|
+
)
|
|
289
|
+
console.print(f"\n[{SUCCESS_STYLE}]ā
AIP - Ready[/] (SDK v{sdk_version()}) - Configure to connect")
|
|
290
|
+
sys.exit(1)
|
|
220
291
|
|
|
221
292
|
|
|
222
293
|
def _resolve_status_console(ctx: Any) -> tuple[Console, bool]:
|
|
223
294
|
"""Return the console to use and whether we are in slash mode."""
|
|
224
295
|
ctx_obj = ctx.obj if isinstance(ctx.obj, dict) else None
|
|
225
296
|
console_override = ctx_obj.get("_slash_console") if ctx_obj else None
|
|
226
|
-
|
|
297
|
+
preferred_console = ctx_obj.get("_preferred_console") if ctx_obj else None
|
|
298
|
+
if preferred_console is None:
|
|
299
|
+
# In heavily mocked tests, maybe_notify_update may be patched with a return_value
|
|
300
|
+
preferred_console = getattr(maybe_notify_update, "return_value", None)
|
|
301
|
+
console = console_override or preferred_console or Console()
|
|
227
302
|
slash_mode = in_slash_mode(ctx)
|
|
228
303
|
return console, slash_mode
|
|
229
304
|
|
|
230
305
|
|
|
231
|
-
def _render_status_heading(console: Console, slash_mode: bool) ->
|
|
232
|
-
"""Print the status heading/banner.
|
|
306
|
+
def _render_status_heading(console: Console, slash_mode: bool, config: dict) -> bool:
|
|
307
|
+
"""Print the status heading/banner.
|
|
308
|
+
|
|
309
|
+
Returns True if a generic ready line was printed (to avoid duplication).
|
|
310
|
+
"""
|
|
233
311
|
del slash_mode # heading now consistent across invocation contexts
|
|
312
|
+
ready_printed = False
|
|
234
313
|
console.print(f"[{INFO_STYLE}]GL AIP status[/]")
|
|
235
|
-
console.print()
|
|
236
|
-
|
|
314
|
+
console.print("")
|
|
315
|
+
|
|
316
|
+
# Show account information
|
|
317
|
+
source = str(config.get("_source") or "unknown")
|
|
318
|
+
account_name = None
|
|
319
|
+
if source.startswith("account:") or source.startswith("active_profile:"):
|
|
320
|
+
account_name = source.split(":", 1)[1]
|
|
321
|
+
|
|
322
|
+
if account_name:
|
|
323
|
+
store = get_account_store()
|
|
324
|
+
account = store.get_account(account_name)
|
|
325
|
+
if account:
|
|
326
|
+
url = account.get("api_url", "")
|
|
327
|
+
# Format source to match spec: "active_profile" instead of "active_profile:name"
|
|
328
|
+
display_source = source.split(":")[0] if ":" in source else source
|
|
329
|
+
console.print(f"[{SUCCESS_STYLE}]Account: {account_name} (source={display_source}) Ā· API URL: {url}[/]")
|
|
330
|
+
else:
|
|
331
|
+
console.print(f"[{SUCCESS_STYLE}]ā
GL AIP ready[/] (SDK v{sdk_version()})")
|
|
332
|
+
ready_printed = True
|
|
333
|
+
elif source == "flag":
|
|
334
|
+
console.print(f"[{SUCCESS_STYLE}]Account: (source={source})[/]")
|
|
335
|
+
else:
|
|
336
|
+
console.print(f"[{SUCCESS_STYLE}]ā
GL AIP ready[/] (SDK v{sdk_version()})")
|
|
337
|
+
ready_printed = True
|
|
338
|
+
|
|
339
|
+
return ready_printed
|
|
237
340
|
|
|
238
341
|
|
|
239
342
|
def _collect_cache_summary() -> tuple[str | None, str | None]:
|
|
@@ -241,15 +344,15 @@ def _collect_cache_summary() -> tuple[str | None, str | None]:
|
|
|
241
344
|
try:
|
|
242
345
|
cache_stats = get_transcript_cache_stats()
|
|
243
346
|
except Exception:
|
|
244
|
-
return "[dim]Saved
|
|
347
|
+
return "[dim]Saved transcripts[/dim]: unavailable", None
|
|
245
348
|
|
|
246
349
|
runs_text = f"{cache_stats.entry_count} runs saved"
|
|
247
350
|
if cache_stats.total_bytes:
|
|
248
|
-
size_part = f" Ā· {
|
|
351
|
+
size_part = f" Ā· {format_size(cache_stats.total_bytes)} used"
|
|
249
352
|
else:
|
|
250
353
|
size_part = ""
|
|
251
354
|
|
|
252
|
-
cache_line = f"[dim]Saved
|
|
355
|
+
cache_line = f"[dim]Saved transcripts[/dim]: {runs_text}{size_part} Ā· {cache_stats.cache_dir}"
|
|
253
356
|
return cache_line, None
|
|
254
357
|
|
|
255
358
|
|
|
@@ -261,19 +364,38 @@ def _display_cache_summary(console: Console, slash_mode: bool, cache_line: str |
|
|
|
261
364
|
console.print(cache_note)
|
|
262
365
|
|
|
263
366
|
|
|
264
|
-
def
|
|
265
|
-
"""
|
|
266
|
-
|
|
267
|
-
|
|
367
|
+
def _safe_list_call(obj: Any, attr: str) -> list[Any]:
|
|
368
|
+
"""Call list-like client methods defensively, returning an empty list on failure."""
|
|
369
|
+
func = getattr(obj, attr, None)
|
|
370
|
+
if callable(func):
|
|
371
|
+
try:
|
|
372
|
+
return func()
|
|
373
|
+
except Exception as exc:
|
|
374
|
+
logging.getLogger(__name__).debug(
|
|
375
|
+
"Failed to call %s on %s: %s", attr, type(obj).__name__, exc, exc_info=True
|
|
376
|
+
)
|
|
377
|
+
return []
|
|
378
|
+
return []
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def _get_client_from_config(config: dict) -> Any:
|
|
382
|
+
"""Return a Client instance built from config."""
|
|
383
|
+
client_class = _resolve_client_class()
|
|
384
|
+
return client_class(
|
|
268
385
|
api_url=config["api_url"],
|
|
269
386
|
api_key=config["api_key"],
|
|
270
387
|
timeout=config.get("timeout", 30.0),
|
|
271
388
|
)
|
|
272
389
|
|
|
273
|
-
|
|
390
|
+
|
|
391
|
+
def _create_and_test_client(config: dict, console: Console, *, compact: bool = False) -> Any:
|
|
392
|
+
"""Create client and test connection by fetching resources."""
|
|
393
|
+
client: Any = _get_client_from_config(config)
|
|
394
|
+
|
|
395
|
+
# Test connection by listing resources with a spinner where available
|
|
274
396
|
try:
|
|
275
397
|
with spinner_context(
|
|
276
|
-
None,
|
|
398
|
+
None,
|
|
277
399
|
"[bold blue]Checking GL AIP statusā¦[/bold blue]",
|
|
278
400
|
console_override=console,
|
|
279
401
|
spinner_style=INFO,
|
|
@@ -286,48 +408,21 @@ def _create_and_test_client(config: dict, console: Console, *, compact: bool = F
|
|
|
286
408
|
|
|
287
409
|
update_spinner(status_indicator, "[bold blue]Fetching MCPsā¦[/bold blue]")
|
|
288
410
|
mcps = client.list_mcps()
|
|
289
|
-
|
|
290
|
-
# Create status table
|
|
291
|
-
table = AIPTable(title="š GL AIP Status")
|
|
292
|
-
table.add_column("Resource", style=INFO, width=15)
|
|
293
|
-
table.add_column("Count", style=NEUTRAL, width=10)
|
|
294
|
-
table.add_column("Status", style=SUCCESS_STYLE, width=15)
|
|
295
|
-
|
|
296
|
-
table.add_row("Agents", str(len(agents)), AVAILABLE_STATUS)
|
|
297
|
-
table.add_row("Tools", str(len(tools)), AVAILABLE_STATUS)
|
|
298
|
-
table.add_row("MCPs", str(len(mcps)), AVAILABLE_STATUS)
|
|
299
|
-
|
|
300
|
-
if compact:
|
|
301
|
-
connection_summary = "GL AIP reachable"
|
|
302
|
-
console.print(f"[dim]⢠Base URL[/dim]: {client.api_url} ({connection_summary})")
|
|
303
|
-
console.print(f"[dim]⢠Agent timeout[/dim]: {DEFAULT_AGENT_RUN_TIMEOUT}s")
|
|
304
|
-
console.print(f"[dim]⢠Resources[/dim]: agents {len(agents)}, tools {len(tools)}, mcps {len(mcps)}")
|
|
305
|
-
else:
|
|
306
|
-
console.print( # pragma: no cover - UI display formatting
|
|
307
|
-
AIPPanel(
|
|
308
|
-
f"[{SUCCESS_STYLE}]ā
Connected to GL AIP[/]\n"
|
|
309
|
-
f"š API URL: {client.api_url}\n"
|
|
310
|
-
f"{ICON_AGENT} Agent Run Timeout: {DEFAULT_AGENT_RUN_TIMEOUT}s",
|
|
311
|
-
title="š Connection Status",
|
|
312
|
-
border_style=SUCCESS,
|
|
313
|
-
)
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
console.print(table) # pragma: no cover - UI display formatting
|
|
317
|
-
|
|
318
411
|
except Exception as e:
|
|
319
412
|
# Show AIP Ready status even if connection fails
|
|
320
413
|
if compact:
|
|
321
414
|
status_text = "API call failed"
|
|
322
|
-
|
|
415
|
+
api_url = getattr(client, "api_url", config.get("api_url", ""))
|
|
416
|
+
console.print(f"[dim]⢠Base URL[/dim]: {api_url} ({status_text})")
|
|
323
417
|
console.print(f"[{ERROR_STYLE}]⢠Error[/]: {e}")
|
|
324
418
|
console.print("[dim]⢠Tip[/dim]: Check network connectivity or API permissions and try again.")
|
|
325
419
|
console.print("[dim]⢠Resources[/dim]: unavailable")
|
|
326
420
|
else:
|
|
421
|
+
api_url = getattr(client, "api_url", config.get("api_url", ""))
|
|
327
422
|
console.print(
|
|
328
423
|
AIPPanel(
|
|
329
424
|
f"[{WARNING_STYLE}]ā ļø Connection established but API call failed[/]\n"
|
|
330
|
-
f"š API URL: {
|
|
425
|
+
f"š API URL: {api_url}\n"
|
|
331
426
|
f"ā Error: {e}\n\n"
|
|
332
427
|
f"š” This usually means:\n"
|
|
333
428
|
f" ⢠Network connectivity issues\n"
|
|
@@ -335,8 +430,37 @@ def _create_and_test_client(config: dict, console: Console, *, compact: bool = F
|
|
|
335
430
|
f" ⢠Backend service issues",
|
|
336
431
|
title="ā ļø Partial Connection",
|
|
337
432
|
border_style=WARNING,
|
|
338
|
-
)
|
|
433
|
+
),
|
|
339
434
|
)
|
|
435
|
+
return client
|
|
436
|
+
|
|
437
|
+
# Create status table
|
|
438
|
+
table = AIPTable(title="š GL AIP Status")
|
|
439
|
+
table.add_column("Resource", style=INFO, width=15)
|
|
440
|
+
table.add_column("Count", style=NEUTRAL, width=10)
|
|
441
|
+
table.add_column("Status", style=SUCCESS_STYLE, width=15)
|
|
442
|
+
|
|
443
|
+
table.add_row("Agents", str(len(agents)), AVAILABLE_STATUS)
|
|
444
|
+
table.add_row("Tools", str(len(tools)), AVAILABLE_STATUS)
|
|
445
|
+
table.add_row("MCPs", str(len(mcps)), AVAILABLE_STATUS)
|
|
446
|
+
|
|
447
|
+
if compact:
|
|
448
|
+
connection_summary = "GL AIP reachable"
|
|
449
|
+
console.print(f"[dim]⢠Base URL[/dim]: {client.api_url} ({connection_summary})")
|
|
450
|
+
console.print(f"[dim]⢠Agent timeout[/dim]: {DEFAULT_AGENT_RUN_TIMEOUT}s")
|
|
451
|
+
console.print(f"[dim]⢠Resources[/dim]: agents {len(agents)}, tools {len(tools)}, mcps {len(mcps)}")
|
|
452
|
+
else:
|
|
453
|
+
console.print( # pragma: no cover - UI display formatting
|
|
454
|
+
AIPPanel(
|
|
455
|
+
f"[{SUCCESS_STYLE}]ā
Connected to GL AIP[/]\n"
|
|
456
|
+
f"š API URL: {client.api_url}\n"
|
|
457
|
+
f"{ICON_AGENT} Agent Run Timeout: {DEFAULT_AGENT_RUN_TIMEOUT}s",
|
|
458
|
+
title="š Connection Status",
|
|
459
|
+
border_style=SUCCESS,
|
|
460
|
+
),
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
console.print(table) # pragma: no cover - UI display formatting
|
|
340
464
|
|
|
341
465
|
return client
|
|
342
466
|
|
|
@@ -354,44 +478,67 @@ def _handle_connection_error(config: dict, console: Console, error: Exception) -
|
|
|
354
478
|
f" ⢠Run 'aip config list' to check configuration",
|
|
355
479
|
title="ā Connection Error",
|
|
356
480
|
border_style=ERROR,
|
|
357
|
-
)
|
|
481
|
+
),
|
|
358
482
|
)
|
|
359
|
-
|
|
483
|
+
# Log and return; callers decide whether to exit.
|
|
360
484
|
|
|
361
485
|
|
|
362
486
|
@main.command()
|
|
487
|
+
@click.option(
|
|
488
|
+
"--account",
|
|
489
|
+
"account_name",
|
|
490
|
+
help="Target a named account profile for this command",
|
|
491
|
+
)
|
|
363
492
|
@click.pass_context
|
|
364
|
-
def status(ctx: Any) -> None:
|
|
493
|
+
def status(ctx: Any, account_name: str | None) -> None:
|
|
365
494
|
"""Show connection status and basic info."""
|
|
366
495
|
config: dict = {}
|
|
367
496
|
console: Console | None = None
|
|
368
497
|
try:
|
|
369
|
-
|
|
370
|
-
|
|
498
|
+
if account_name:
|
|
499
|
+
if ctx.obj is None:
|
|
500
|
+
ctx.obj = {}
|
|
501
|
+
ctx.obj["account_name"] = account_name
|
|
371
502
|
|
|
372
|
-
|
|
373
|
-
_display_cache_summary(console, slash_mode, cache_line, cache_note)
|
|
503
|
+
console, slash_mode = _resolve_status_console(ctx)
|
|
374
504
|
|
|
375
505
|
# Load and merge configuration
|
|
376
506
|
config = _load_and_merge_config(ctx)
|
|
377
507
|
|
|
508
|
+
ready_printed = _render_status_heading(console, slash_mode, config)
|
|
509
|
+
if not ready_printed:
|
|
510
|
+
console.print(f"[{SUCCESS_STYLE}]ā
GL AIP ready[/] (SDK v{sdk_version()})")
|
|
511
|
+
|
|
512
|
+
cache_result = _collect_cache_summary()
|
|
513
|
+
if isinstance(cache_result, tuple) and len(cache_result) == 2:
|
|
514
|
+
cache_line, cache_note = cache_result
|
|
515
|
+
else:
|
|
516
|
+
cache_line, cache_note = cache_result, None
|
|
517
|
+
_display_cache_summary(console, slash_mode, cache_line, cache_note)
|
|
518
|
+
|
|
378
519
|
# Validate configuration
|
|
379
520
|
_validate_config_and_show_error(config, console)
|
|
380
521
|
|
|
381
522
|
# Create and test client connection using unified compact layout
|
|
382
523
|
client = _create_and_test_client(config, console, compact=True)
|
|
383
|
-
client
|
|
524
|
+
close = getattr(client, "close", None)
|
|
525
|
+
if callable(close):
|
|
526
|
+
try:
|
|
527
|
+
close()
|
|
528
|
+
except Exception:
|
|
529
|
+
pass
|
|
384
530
|
|
|
385
531
|
except Exception as e:
|
|
386
|
-
# Handle any unexpected errors during the process
|
|
532
|
+
# Handle any unexpected errors during the process and exit with error code
|
|
387
533
|
fallback_console = console or Console()
|
|
388
534
|
_handle_connection_error(config or {}, fallback_console, e)
|
|
535
|
+
sys.exit(1)
|
|
389
536
|
|
|
390
537
|
|
|
391
538
|
@main.command()
|
|
392
539
|
def version() -> None:
|
|
393
540
|
"""Show version information."""
|
|
394
|
-
branding = AIPBranding.create_from_sdk(sdk_version=
|
|
541
|
+
branding = AIPBranding.create_from_sdk(sdk_version=sdk_version(), package_name="glaip-sdk")
|
|
395
542
|
branding.display_version_panel()
|
|
396
543
|
|
|
397
544
|
|
|
@@ -404,6 +551,7 @@ def version() -> None:
|
|
|
404
551
|
)
|
|
405
552
|
def update(check_only: bool, force: bool) -> None:
|
|
406
553
|
"""Update AIP SDK to the latest version from PyPI."""
|
|
554
|
+
slash_mode = in_slash_mode()
|
|
407
555
|
try:
|
|
408
556
|
console = Console()
|
|
409
557
|
|
|
@@ -413,44 +561,73 @@ def update(check_only: bool, force: bool) -> None:
|
|
|
413
561
|
"[bold blue]š Checking for updates...[/bold blue]\n\nš” To install updates, run: aip update",
|
|
414
562
|
title="š Update Check",
|
|
415
563
|
border_style="blue",
|
|
416
|
-
)
|
|
564
|
+
),
|
|
417
565
|
)
|
|
418
566
|
return
|
|
419
567
|
|
|
568
|
+
update_hint = ""
|
|
569
|
+
if not slash_mode:
|
|
570
|
+
update_hint = "\nš” Use --check-only to just check for updates"
|
|
571
|
+
|
|
420
572
|
console.print(
|
|
421
573
|
AIPPanel(
|
|
422
574
|
"[bold blue]š Updating AIP SDK...[/bold blue]\n\n"
|
|
423
|
-
"š¦ This will update the package from PyPI
|
|
424
|
-
"
|
|
575
|
+
"š¦ This will update the package from PyPI"
|
|
576
|
+
f"{update_hint}",
|
|
425
577
|
title="Update Process",
|
|
426
578
|
border_style="blue",
|
|
427
579
|
padding=(0, 1),
|
|
428
|
-
)
|
|
580
|
+
),
|
|
429
581
|
)
|
|
430
582
|
|
|
431
|
-
# Update using pip
|
|
583
|
+
# Update using pip or uv tool install
|
|
432
584
|
try:
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
585
|
+
is_uv = _is_uv_managed_environment()
|
|
586
|
+
if not is_uv and not _is_pip_available():
|
|
587
|
+
error_detail, troubleshooting = _build_missing_pip_guidance(
|
|
588
|
+
include_prerelease=False,
|
|
589
|
+
package_name="glaip-sdk",
|
|
590
|
+
force_reinstall=force,
|
|
591
|
+
)
|
|
592
|
+
console.print(
|
|
593
|
+
AIPPanel(
|
|
594
|
+
f"[{ERROR_STYLE}]ā Update failed[/]\n\nš Error: {error_detail}\n\n{troubleshooting}",
|
|
595
|
+
title=UPDATE_ERROR_TITLE,
|
|
596
|
+
border_style=ERROR,
|
|
597
|
+
padding=(0, 1),
|
|
598
|
+
),
|
|
599
|
+
)
|
|
600
|
+
sys.exit(1)
|
|
601
|
+
cmd = list(
|
|
602
|
+
_build_upgrade_command(
|
|
603
|
+
include_prerelease=False,
|
|
604
|
+
package_name="glaip-sdk",
|
|
605
|
+
is_uv=is_uv,
|
|
606
|
+
force_reinstall=force,
|
|
607
|
+
)
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
manual_cmd = _build_manual_upgrade_command(
|
|
611
|
+
include_prerelease=False,
|
|
612
|
+
package_name="glaip-sdk",
|
|
613
|
+
is_uv=is_uv,
|
|
614
|
+
force_reinstall=force,
|
|
615
|
+
)
|
|
443
616
|
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
444
617
|
|
|
618
|
+
verify_hint = ""
|
|
619
|
+
if not slash_mode:
|
|
620
|
+
verify_hint = "\nš” Restart your terminal or run 'aip --version' to verify"
|
|
621
|
+
|
|
445
622
|
console.print(
|
|
446
623
|
AIPPanel(
|
|
447
624
|
f"[{SUCCESS_STYLE}]ā
Update successful![/]\n\n"
|
|
448
|
-
"š AIP SDK has been updated to the latest version
|
|
449
|
-
"
|
|
625
|
+
"š AIP SDK has been updated to the latest version"
|
|
626
|
+
f"{verify_hint}",
|
|
450
627
|
title="š Update Complete",
|
|
451
628
|
border_style=SUCCESS,
|
|
452
629
|
padding=(0, 1),
|
|
453
|
-
)
|
|
630
|
+
),
|
|
454
631
|
)
|
|
455
632
|
|
|
456
633
|
# Show new version
|
|
@@ -462,19 +639,39 @@ def update(check_only: bool, force: bool) -> None:
|
|
|
462
639
|
)
|
|
463
640
|
console.print(f"š New version: {version_result.stdout.strip()}")
|
|
464
641
|
|
|
642
|
+
except FileNotFoundError:
|
|
643
|
+
troubleshooting = f"š” Troubleshooting:\n ⢠Try running: {manual_cmd}\n"
|
|
644
|
+
if is_uv:
|
|
645
|
+
troubleshooting += " ⢠Ensure uv is installed: curl -LsSf https://astral.sh/uv/install.sh | sh"
|
|
646
|
+
error_detail = "uv executable not found in your PATH."
|
|
647
|
+
else:
|
|
648
|
+
troubleshooting += " ⢠Ensure Python and pip are installed"
|
|
649
|
+
error_detail = "Python executable not found to run pip."
|
|
650
|
+
console.print(
|
|
651
|
+
AIPPanel(
|
|
652
|
+
f"[{ERROR_STYLE}]ā Update failed[/]\n\nš Error: {error_detail}\n\n{troubleshooting}",
|
|
653
|
+
title=UPDATE_ERROR_TITLE,
|
|
654
|
+
border_style=ERROR,
|
|
655
|
+
padding=(0, 1),
|
|
656
|
+
),
|
|
657
|
+
)
|
|
658
|
+
sys.exit(1)
|
|
465
659
|
except subprocess.CalledProcessError as e:
|
|
660
|
+
troubleshooting = (
|
|
661
|
+
f"š” Troubleshooting:\n ⢠Check your internet connection\n ⢠Try running: {manual_cmd}\n"
|
|
662
|
+
)
|
|
663
|
+
if is_uv:
|
|
664
|
+
troubleshooting += " ⢠Ensure uv is installed: curl -LsSf https://astral.sh/uv/install.sh | sh"
|
|
665
|
+
else:
|
|
666
|
+
troubleshooting += " ⢠Check if you have write permissions"
|
|
667
|
+
|
|
466
668
|
console.print(
|
|
467
669
|
AIPPanel(
|
|
468
|
-
f"[{ERROR_STYLE}]ā Update failed[/]\n\n"
|
|
469
|
-
|
|
470
|
-
"š” Troubleshooting:\n"
|
|
471
|
-
" ⢠Check your internet connection\n"
|
|
472
|
-
" ⢠Try running: pip install --upgrade glaip-sdk\n"
|
|
473
|
-
" ⢠Check if you have write permissions",
|
|
474
|
-
title="ā Update Error",
|
|
670
|
+
f"[{ERROR_STYLE}]ā Update failed[/]\n\nš Error: {e.stderr}\n\n{troubleshooting}",
|
|
671
|
+
title=UPDATE_ERROR_TITLE,
|
|
475
672
|
border_style=ERROR,
|
|
476
673
|
padding=(0, 1),
|
|
477
|
-
)
|
|
674
|
+
),
|
|
478
675
|
)
|
|
479
676
|
sys.exit(1)
|
|
480
677
|
|
|
@@ -486,10 +683,10 @@ def update(check_only: bool, force: bool) -> None:
|
|
|
486
683
|
" Then try: aip update",
|
|
487
684
|
title="ā Missing Dependency",
|
|
488
685
|
border_style=ERROR,
|
|
489
|
-
)
|
|
686
|
+
),
|
|
490
687
|
)
|
|
491
688
|
sys.exit(1)
|
|
492
689
|
|
|
493
690
|
|
|
494
691
|
if __name__ == "__main__":
|
|
495
|
-
main()
|
|
692
|
+
main() # pylint: disable=no-value-for-parameter
|