glaip-sdk 0.0.20__py3-none-any.whl ā 0.7.7__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 +10 -3
- glaip_sdk/agents/__init__.py +27 -0
- glaip_sdk/agents/base.py +1250 -0
- glaip_sdk/branding.py +15 -6
- glaip_sdk/cli/account_store.py +540 -0
- glaip_sdk/cli/agent_config.py +2 -6
- glaip_sdk/cli/auth.py +271 -45
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/accounts.py +746 -0
- glaip_sdk/cli/commands/agents/__init__.py +119 -0
- glaip_sdk/cli/commands/agents/_common.py +561 -0
- glaip_sdk/cli/commands/agents/create.py +151 -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 +734 -143
- 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 +14 -12
- 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 +164 -23
- glaip_sdk/cli/config.py +49 -7
- 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 +45 -32
- glaip_sdk/cli/entrypoint.py +20 -0
- glaip_sdk/cli/hints.py +57 -0
- glaip_sdk/cli/io.py +14 -17
- glaip_sdk/cli/main.py +344 -167
- glaip_sdk/cli/masking.py +21 -33
- glaip_sdk/cli/mcp_validators.py +5 -15
- glaip_sdk/cli/pager.py +15 -22
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/parsers/json_input.py +11 -22
- glaip_sdk/cli/resolution.py +5 -10
- glaip_sdk/cli/rich_helpers.py +1 -3
- 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 +65 -29
- glaip_sdk/cli/slash/prompt.py +24 -10
- glaip_sdk/cli/slash/remote_runs_controller.py +566 -0
- glaip_sdk/cli/slash/session.py +827 -232
- glaip_sdk/cli/slash/tui/__init__.py +34 -0
- glaip_sdk/cli/slash/tui/accounts.tcss +88 -0
- glaip_sdk/cli/slash/tui/accounts_app.py +933 -0
- glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
- glaip_sdk/cli/slash/tui/clipboard.py +147 -0
- glaip_sdk/cli/slash/tui/context.py +59 -0
- glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
- glaip_sdk/cli/slash/tui/loading.py +58 -0
- glaip_sdk/cli/slash/tui/remote_runs_app.py +628 -0
- glaip_sdk/cli/slash/tui/terminal.py +402 -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 +86 -0
- glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
- glaip_sdk/cli/slash/tui/toast.py +123 -0
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +258 -60
- glaip_sdk/cli/transcript/capture.py +72 -21
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/launcher.py +1 -3
- glaip_sdk/cli/transcript/viewer.py +79 -329
- glaip_sdk/cli/update_notifier.py +385 -24
- glaip_sdk/cli/validators.py +16 -18
- 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 +370 -100
- glaip_sdk/client/base.py +78 -35
- glaip_sdk/client/hitl.py +136 -0
- glaip_sdk/client/main.py +25 -10
- glaip_sdk/client/mcps.py +166 -27
- glaip_sdk/client/payloads/agent/__init__.py +23 -0
- glaip_sdk/client/{_agent_payloads.py ā payloads/agent/requests.py} +65 -74
- glaip_sdk/client/payloads/agent/responses.py +43 -0
- glaip_sdk/client/run_rendering.py +583 -79
- glaip_sdk/client/schedules.py +439 -0
- glaip_sdk/client/shared.py +21 -0
- glaip_sdk/client/tools.py +214 -56
- glaip_sdk/client/validators.py +20 -48
- glaip_sdk/config/constants.py +11 -0
- glaip_sdk/exceptions.py +1 -3
- 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/icons.py +9 -3
- glaip_sdk/mcps/__init__.py +21 -0
- glaip_sdk/mcps/base.py +345 -0
- glaip_sdk/models/__init__.py +107 -0
- glaip_sdk/models/agent.py +47 -0
- glaip_sdk/models/agent_runs.py +117 -0
- glaip_sdk/models/common.py +42 -0
- glaip_sdk/models/mcp.py +33 -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 -3
- 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 +112 -0
- glaip_sdk/runner/langgraph.py +872 -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 +95 -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 +468 -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 +4 -14
- glaip_sdk/utils/bundler.py +403 -0
- glaip_sdk/utils/client.py +111 -0
- glaip_sdk/utils/client_utils.py +46 -28
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/discovery.py +78 -0
- glaip_sdk/utils/display.py +25 -21
- glaip_sdk/utils/export.py +143 -0
- glaip_sdk/utils/general.py +1 -36
- glaip_sdk/utils/import_export.py +15 -16
- 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 +38 -23
- glaip_sdk/utils/rendering/layout/__init__.py +64 -0
- glaip_sdk/utils/rendering/{renderer ā layout}/panels.py +10 -3
- glaip_sdk/utils/rendering/{renderer ā layout}/progress.py +73 -12
- glaip_sdk/utils/rendering/layout/summary.py +74 -0
- glaip_sdk/utils/rendering/layout/transcript.py +606 -0
- glaip_sdk/utils/rendering/models.py +18 -8
- glaip_sdk/utils/rendering/renderer/__init__.py +9 -51
- glaip_sdk/utils/rendering/renderer/base.py +534 -882
- glaip_sdk/utils/rendering/renderer/config.py +4 -10
- glaip_sdk/utils/rendering/renderer/debug.py +30 -34
- glaip_sdk/utils/rendering/renderer/factory.py +138 -0
- glaip_sdk/utils/rendering/renderer/stream.py +13 -54
- glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
- glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
- glaip_sdk/utils/rendering/renderer/toggle.py +182 -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/step_tree_state.py +100 -0
- glaip_sdk/utils/rendering/steps/__init__.py +34 -0
- glaip_sdk/utils/rendering/steps/event_processor.py +778 -0
- glaip_sdk/utils/rendering/steps/format.py +176 -0
- glaip_sdk/utils/rendering/{steps.py ā steps/manager.py} +122 -26
- 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 +29 -26
- glaip_sdk/utils/runtime_config.py +425 -0
- glaip_sdk/utils/serialization.py +32 -46
- 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 +20 -28
- {glaip_sdk-0.0.20.dist-info ā glaip_sdk-0.7.7.dist-info}/METADATA +78 -23
- glaip_sdk-0.7.7.dist-info/RECORD +213 -0
- {glaip_sdk-0.0.20.dist-info ā glaip_sdk-0.7.7.dist-info}/WHEEL +2 -1
- glaip_sdk-0.7.7.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.7.7.dist-info/top_level.txt +1 -0
- glaip_sdk/cli/commands/agents.py +0 -1412
- glaip_sdk/cli/commands/mcps.py +0 -1225
- glaip_sdk/cli/commands/tools.py +0 -597
- glaip_sdk/cli/utils.py +0 -1330
- glaip_sdk/models.py +0 -259
- glaip_sdk-0.0.20.dist-info/RECORD +0 -80
- glaip_sdk-0.0.20.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,61 +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
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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)
|
|
222
291
|
|
|
223
292
|
|
|
224
293
|
def _resolve_status_console(ctx: Any) -> tuple[Console, bool]:
|
|
225
294
|
"""Return the console to use and whether we are in slash mode."""
|
|
226
295
|
ctx_obj = ctx.obj if isinstance(ctx.obj, dict) else None
|
|
227
296
|
console_override = ctx_obj.get("_slash_console") if ctx_obj else None
|
|
228
|
-
|
|
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()
|
|
229
302
|
slash_mode = in_slash_mode(ctx)
|
|
230
303
|
return console, slash_mode
|
|
231
304
|
|
|
232
305
|
|
|
233
|
-
def _render_status_heading(console: Console, slash_mode: bool) ->
|
|
234
|
-
"""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
|
+
"""
|
|
235
311
|
del slash_mode # heading now consistent across invocation contexts
|
|
312
|
+
ready_printed = False
|
|
236
313
|
console.print(f"[{INFO_STYLE}]GL AIP status[/]")
|
|
237
|
-
console.print()
|
|
238
|
-
|
|
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
|
|
239
340
|
|
|
240
341
|
|
|
241
342
|
def _collect_cache_summary() -> tuple[str | None, str | None]:
|
|
@@ -243,24 +344,19 @@ def _collect_cache_summary() -> tuple[str | None, str | None]:
|
|
|
243
344
|
try:
|
|
244
345
|
cache_stats = get_transcript_cache_stats()
|
|
245
346
|
except Exception:
|
|
246
|
-
return "[dim]Saved
|
|
347
|
+
return "[dim]Saved transcripts[/dim]: unavailable", None
|
|
247
348
|
|
|
248
349
|
runs_text = f"{cache_stats.entry_count} runs saved"
|
|
249
350
|
if cache_stats.total_bytes:
|
|
250
|
-
size_part = f" Ā· {
|
|
351
|
+
size_part = f" Ā· {format_size(cache_stats.total_bytes)} used"
|
|
251
352
|
else:
|
|
252
353
|
size_part = ""
|
|
253
354
|
|
|
254
|
-
cache_line =
|
|
255
|
-
f"[dim]Saved run history[/dim]: {runs_text}{size_part}"
|
|
256
|
-
f" Ā· {cache_stats.cache_dir}"
|
|
257
|
-
)
|
|
355
|
+
cache_line = f"[dim]Saved transcripts[/dim]: {runs_text}{size_part} Ā· {cache_stats.cache_dir}"
|
|
258
356
|
return cache_line, None
|
|
259
357
|
|
|
260
358
|
|
|
261
|
-
def _display_cache_summary(
|
|
262
|
-
console: Console, slash_mode: bool, cache_line: str | None, cache_note: str | None
|
|
263
|
-
) -> None:
|
|
359
|
+
def _display_cache_summary(console: Console, slash_mode: bool, cache_line: str | None, cache_note: str | None) -> None:
|
|
264
360
|
"""Render the cache summary details."""
|
|
265
361
|
if cache_line:
|
|
266
362
|
console.print(cache_line)
|
|
@@ -268,21 +364,38 @@ def _display_cache_summary(
|
|
|
268
364
|
console.print(cache_note)
|
|
269
365
|
|
|
270
366
|
|
|
271
|
-
def
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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(
|
|
277
385
|
api_url=config["api_url"],
|
|
278
386
|
api_key=config["api_key"],
|
|
279
387
|
timeout=config.get("timeout", 30.0),
|
|
280
388
|
)
|
|
281
389
|
|
|
282
|
-
|
|
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
|
|
283
396
|
try:
|
|
284
397
|
with spinner_context(
|
|
285
|
-
None,
|
|
398
|
+
None,
|
|
286
399
|
"[bold blue]Checking GL AIP statusā¦[/bold blue]",
|
|
287
400
|
console_override=console,
|
|
288
401
|
spinner_style=INFO,
|
|
@@ -295,54 +408,21 @@ def _create_and_test_client(
|
|
|
295
408
|
|
|
296
409
|
update_spinner(status_indicator, "[bold blue]Fetching MCPsā¦[/bold blue]")
|
|
297
410
|
mcps = client.list_mcps()
|
|
298
|
-
|
|
299
|
-
# Create status table
|
|
300
|
-
table = AIPTable(title="š GL AIP Status")
|
|
301
|
-
table.add_column("Resource", style=INFO, width=15)
|
|
302
|
-
table.add_column("Count", style=NEUTRAL, width=10)
|
|
303
|
-
table.add_column("Status", style=SUCCESS_STYLE, width=15)
|
|
304
|
-
|
|
305
|
-
table.add_row("Agents", str(len(agents)), AVAILABLE_STATUS)
|
|
306
|
-
table.add_row("Tools", str(len(tools)), AVAILABLE_STATUS)
|
|
307
|
-
table.add_row("MCPs", str(len(mcps)), AVAILABLE_STATUS)
|
|
308
|
-
|
|
309
|
-
if compact:
|
|
310
|
-
connection_summary = "GL AIP reachable"
|
|
311
|
-
console.print(
|
|
312
|
-
f"[dim]⢠Base URL[/dim]: {client.api_url} ({connection_summary})"
|
|
313
|
-
)
|
|
314
|
-
console.print(f"[dim]⢠Agent timeout[/dim]: {DEFAULT_AGENT_RUN_TIMEOUT}s")
|
|
315
|
-
console.print(
|
|
316
|
-
f"[dim]⢠Resources[/dim]: agents {len(agents)}, tools {len(tools)}, mcps {len(mcps)}"
|
|
317
|
-
)
|
|
318
|
-
else:
|
|
319
|
-
console.print( # pragma: no cover - UI display formatting
|
|
320
|
-
AIPPanel(
|
|
321
|
-
f"[{SUCCESS_STYLE}]ā
Connected to GL AIP[/]\n"
|
|
322
|
-
f"š API URL: {client.api_url}\n"
|
|
323
|
-
f"{ICON_AGENT} Agent Run Timeout: {DEFAULT_AGENT_RUN_TIMEOUT}s",
|
|
324
|
-
title="š Connection Status",
|
|
325
|
-
border_style=SUCCESS,
|
|
326
|
-
)
|
|
327
|
-
)
|
|
328
|
-
|
|
329
|
-
console.print(table) # pragma: no cover - UI display formatting
|
|
330
|
-
|
|
331
411
|
except Exception as e:
|
|
332
412
|
# Show AIP Ready status even if connection fails
|
|
333
413
|
if compact:
|
|
334
414
|
status_text = "API call failed"
|
|
335
|
-
|
|
415
|
+
api_url = getattr(client, "api_url", config.get("api_url", ""))
|
|
416
|
+
console.print(f"[dim]⢠Base URL[/dim]: {api_url} ({status_text})")
|
|
336
417
|
console.print(f"[{ERROR_STYLE}]⢠Error[/]: {e}")
|
|
337
|
-
console.print(
|
|
338
|
-
"[dim]⢠Tip[/dim]: Check network connectivity or API permissions and try again."
|
|
339
|
-
)
|
|
418
|
+
console.print("[dim]⢠Tip[/dim]: Check network connectivity or API permissions and try again.")
|
|
340
419
|
console.print("[dim]⢠Resources[/dim]: unavailable")
|
|
341
420
|
else:
|
|
421
|
+
api_url = getattr(client, "api_url", config.get("api_url", ""))
|
|
342
422
|
console.print(
|
|
343
423
|
AIPPanel(
|
|
344
424
|
f"[{WARNING_STYLE}]ā ļø Connection established but API call failed[/]\n"
|
|
345
|
-
f"š API URL: {
|
|
425
|
+
f"š API URL: {api_url}\n"
|
|
346
426
|
f"ā Error: {e}\n\n"
|
|
347
427
|
f"š” This usually means:\n"
|
|
348
428
|
f" ⢠Network connectivity issues\n"
|
|
@@ -350,8 +430,37 @@ def _create_and_test_client(
|
|
|
350
430
|
f" ⢠Backend service issues",
|
|
351
431
|
title="ā ļø Partial Connection",
|
|
352
432
|
border_style=WARNING,
|
|
353
|
-
)
|
|
433
|
+
),
|
|
354
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
|
|
355
464
|
|
|
356
465
|
return client
|
|
357
466
|
|
|
@@ -369,53 +478,72 @@ def _handle_connection_error(config: dict, console: Console, error: Exception) -
|
|
|
369
478
|
f" ⢠Run 'aip config list' to check configuration",
|
|
370
479
|
title="ā Connection Error",
|
|
371
480
|
border_style=ERROR,
|
|
372
|
-
)
|
|
481
|
+
),
|
|
373
482
|
)
|
|
374
|
-
|
|
483
|
+
# Log and return; callers decide whether to exit.
|
|
375
484
|
|
|
376
485
|
|
|
377
486
|
@main.command()
|
|
487
|
+
@click.option(
|
|
488
|
+
"--account",
|
|
489
|
+
"account_name",
|
|
490
|
+
help="Target a named account profile for this command",
|
|
491
|
+
)
|
|
378
492
|
@click.pass_context
|
|
379
|
-
def status(ctx: Any) -> None:
|
|
493
|
+
def status(ctx: Any, account_name: str | None) -> None:
|
|
380
494
|
"""Show connection status and basic info."""
|
|
381
495
|
config: dict = {}
|
|
382
496
|
console: Console | None = None
|
|
383
497
|
try:
|
|
384
|
-
|
|
385
|
-
|
|
498
|
+
if account_name:
|
|
499
|
+
if ctx.obj is None:
|
|
500
|
+
ctx.obj = {}
|
|
501
|
+
ctx.obj["account_name"] = account_name
|
|
386
502
|
|
|
387
|
-
|
|
388
|
-
_display_cache_summary(console, slash_mode, cache_line, cache_note)
|
|
503
|
+
console, slash_mode = _resolve_status_console(ctx)
|
|
389
504
|
|
|
390
505
|
# Load and merge configuration
|
|
391
506
|
config = _load_and_merge_config(ctx)
|
|
392
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
|
+
|
|
393
519
|
# Validate configuration
|
|
394
520
|
_validate_config_and_show_error(config, console)
|
|
395
521
|
|
|
396
522
|
# Create and test client connection using unified compact layout
|
|
397
523
|
client = _create_and_test_client(config, console, compact=True)
|
|
398
|
-
client
|
|
524
|
+
close = getattr(client, "close", None)
|
|
525
|
+
if callable(close):
|
|
526
|
+
try:
|
|
527
|
+
close()
|
|
528
|
+
except Exception:
|
|
529
|
+
pass
|
|
399
530
|
|
|
400
531
|
except Exception as e:
|
|
401
|
-
# Handle any unexpected errors during the process
|
|
532
|
+
# Handle any unexpected errors during the process and exit with error code
|
|
402
533
|
fallback_console = console or Console()
|
|
403
534
|
_handle_connection_error(config or {}, fallback_console, e)
|
|
535
|
+
sys.exit(1)
|
|
404
536
|
|
|
405
537
|
|
|
406
538
|
@main.command()
|
|
407
539
|
def version() -> None:
|
|
408
540
|
"""Show version information."""
|
|
409
|
-
branding = AIPBranding.create_from_sdk(
|
|
410
|
-
sdk_version=_SDK_VERSION, package_name="glaip-sdk"
|
|
411
|
-
)
|
|
541
|
+
branding = AIPBranding.create_from_sdk(sdk_version=sdk_version(), package_name="glaip-sdk")
|
|
412
542
|
branding.display_version_panel()
|
|
413
543
|
|
|
414
544
|
|
|
415
545
|
@main.command()
|
|
416
|
-
@click.option(
|
|
417
|
-
"--check-only", is_flag=True, help="Only check for updates without installing"
|
|
418
|
-
)
|
|
546
|
+
@click.option("--check-only", is_flag=True, help="Only check for updates without installing")
|
|
419
547
|
@click.option(
|
|
420
548
|
"--force",
|
|
421
549
|
is_flag=True,
|
|
@@ -423,54 +551,83 @@ def version() -> None:
|
|
|
423
551
|
)
|
|
424
552
|
def update(check_only: bool, force: bool) -> None:
|
|
425
553
|
"""Update AIP SDK to the latest version from PyPI."""
|
|
554
|
+
slash_mode = in_slash_mode()
|
|
426
555
|
try:
|
|
427
556
|
console = Console()
|
|
428
557
|
|
|
429
558
|
if check_only:
|
|
430
559
|
console.print(
|
|
431
560
|
AIPPanel(
|
|
432
|
-
"[bold blue]š Checking for updates...[/bold blue]\n\n"
|
|
433
|
-
"š” To install updates, run: aip update",
|
|
561
|
+
"[bold blue]š Checking for updates...[/bold blue]\n\nš” To install updates, run: aip update",
|
|
434
562
|
title="š Update Check",
|
|
435
563
|
border_style="blue",
|
|
436
|
-
)
|
|
564
|
+
),
|
|
437
565
|
)
|
|
438
566
|
return
|
|
439
567
|
|
|
568
|
+
update_hint = ""
|
|
569
|
+
if not slash_mode:
|
|
570
|
+
update_hint = "\nš” Use --check-only to just check for updates"
|
|
571
|
+
|
|
440
572
|
console.print(
|
|
441
573
|
AIPPanel(
|
|
442
574
|
"[bold blue]š Updating AIP SDK...[/bold blue]\n\n"
|
|
443
|
-
"š¦ This will update the package from PyPI
|
|
444
|
-
"
|
|
575
|
+
"š¦ This will update the package from PyPI"
|
|
576
|
+
f"{update_hint}",
|
|
445
577
|
title="Update Process",
|
|
446
578
|
border_style="blue",
|
|
447
579
|
padding=(0, 1),
|
|
448
|
-
)
|
|
580
|
+
),
|
|
449
581
|
)
|
|
450
582
|
|
|
451
|
-
# Update using pip
|
|
583
|
+
# Update using pip or uv tool install
|
|
452
584
|
try:
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
+
)
|
|
463
616
|
subprocess.run(cmd, capture_output=True, text=True, check=True)
|
|
464
617
|
|
|
618
|
+
verify_hint = ""
|
|
619
|
+
if not slash_mode:
|
|
620
|
+
verify_hint = "\nš” Restart your terminal or run 'aip --version' to verify"
|
|
621
|
+
|
|
465
622
|
console.print(
|
|
466
623
|
AIPPanel(
|
|
467
624
|
f"[{SUCCESS_STYLE}]ā
Update successful![/]\n\n"
|
|
468
|
-
"š AIP SDK has been updated to the latest version
|
|
469
|
-
"
|
|
625
|
+
"š AIP SDK has been updated to the latest version"
|
|
626
|
+
f"{verify_hint}",
|
|
470
627
|
title="š Update Complete",
|
|
471
628
|
border_style=SUCCESS,
|
|
472
629
|
padding=(0, 1),
|
|
473
|
-
)
|
|
630
|
+
),
|
|
474
631
|
)
|
|
475
632
|
|
|
476
633
|
# Show new version
|
|
@@ -482,19 +639,39 @@ def update(check_only: bool, force: bool) -> None:
|
|
|
482
639
|
)
|
|
483
640
|
console.print(f"š New version: {version_result.stdout.strip()}")
|
|
484
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)
|
|
485
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
|
+
|
|
486
668
|
console.print(
|
|
487
669
|
AIPPanel(
|
|
488
|
-
f"[{ERROR_STYLE}]ā Update failed[/]\n\n"
|
|
489
|
-
|
|
490
|
-
"š” Troubleshooting:\n"
|
|
491
|
-
" ⢠Check your internet connection\n"
|
|
492
|
-
" ⢠Try running: pip install --upgrade glaip-sdk\n"
|
|
493
|
-
" ⢠Check if you have write permissions",
|
|
494
|
-
title="ā Update Error",
|
|
670
|
+
f"[{ERROR_STYLE}]ā Update failed[/]\n\nš Error: {e.stderr}\n\n{troubleshooting}",
|
|
671
|
+
title=UPDATE_ERROR_TITLE,
|
|
495
672
|
border_style=ERROR,
|
|
496
673
|
padding=(0, 1),
|
|
497
|
-
)
|
|
674
|
+
),
|
|
498
675
|
)
|
|
499
676
|
sys.exit(1)
|
|
500
677
|
|
|
@@ -506,10 +683,10 @@ def update(check_only: bool, force: bool) -> None:
|
|
|
506
683
|
" Then try: aip update",
|
|
507
684
|
title="ā Missing Dependency",
|
|
508
685
|
border_style=ERROR,
|
|
509
|
-
)
|
|
686
|
+
),
|
|
510
687
|
)
|
|
511
688
|
sys.exit(1)
|
|
512
689
|
|
|
513
690
|
|
|
514
691
|
if __name__ == "__main__":
|
|
515
|
-
main()
|
|
692
|
+
main() # pylint: disable=no-value-for-parameter
|