glaip-sdk 0.6.12__py3-none-any.whl → 0.6.14__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 +42 -5
- {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.14.dist-info}/METADATA +31 -37
- glaip_sdk-0.6.14.dist-info/RECORD +12 -0
- {glaip_sdk-0.6.12.dist-info → glaip_sdk-0.6.14.dist-info}/WHEEL +2 -1
- glaip_sdk-0.6.14.dist-info/entry_points.txt +2 -0
- glaip_sdk-0.6.14.dist-info/top_level.txt +1 -0
- glaip_sdk/agents/__init__.py +0 -27
- glaip_sdk/agents/base.py +0 -1191
- glaip_sdk/cli/__init__.py +0 -9
- glaip_sdk/cli/account_store.py +0 -540
- glaip_sdk/cli/agent_config.py +0 -78
- glaip_sdk/cli/auth.py +0 -699
- glaip_sdk/cli/commands/__init__.py +0 -5
- glaip_sdk/cli/commands/accounts.py +0 -746
- glaip_sdk/cli/commands/agents.py +0 -1509
- glaip_sdk/cli/commands/common_config.py +0 -101
- glaip_sdk/cli/commands/configure.py +0 -896
- glaip_sdk/cli/commands/mcps.py +0 -1356
- glaip_sdk/cli/commands/models.py +0 -69
- glaip_sdk/cli/commands/tools.py +0 -576
- glaip_sdk/cli/commands/transcripts.py +0 -755
- glaip_sdk/cli/commands/update.py +0 -61
- glaip_sdk/cli/config.py +0 -95
- glaip_sdk/cli/constants.py +0 -38
- glaip_sdk/cli/context.py +0 -150
- glaip_sdk/cli/core/__init__.py +0 -79
- glaip_sdk/cli/core/context.py +0 -124
- glaip_sdk/cli/core/output.py +0 -846
- glaip_sdk/cli/core/prompting.py +0 -649
- glaip_sdk/cli/core/rendering.py +0 -187
- glaip_sdk/cli/display.py +0 -355
- glaip_sdk/cli/hints.py +0 -57
- glaip_sdk/cli/io.py +0 -112
- glaip_sdk/cli/main.py +0 -604
- glaip_sdk/cli/masking.py +0 -136
- glaip_sdk/cli/mcp_validators.py +0 -287
- glaip_sdk/cli/pager.py +0 -266
- glaip_sdk/cli/parsers/__init__.py +0 -7
- glaip_sdk/cli/parsers/json_input.py +0 -177
- glaip_sdk/cli/resolution.py +0 -67
- glaip_sdk/cli/rich_helpers.py +0 -27
- glaip_sdk/cli/slash/__init__.py +0 -15
- glaip_sdk/cli/slash/accounts_controller.py +0 -578
- glaip_sdk/cli/slash/accounts_shared.py +0 -75
- glaip_sdk/cli/slash/agent_session.py +0 -285
- glaip_sdk/cli/slash/prompt.py +0 -256
- glaip_sdk/cli/slash/remote_runs_controller.py +0 -566
- glaip_sdk/cli/slash/session.py +0 -1708
- glaip_sdk/cli/slash/tui/__init__.py +0 -9
- glaip_sdk/cli/slash/tui/accounts_app.py +0 -876
- glaip_sdk/cli/slash/tui/background_tasks.py +0 -72
- glaip_sdk/cli/slash/tui/loading.py +0 -58
- glaip_sdk/cli/slash/tui/remote_runs_app.py +0 -628
- glaip_sdk/cli/transcript/__init__.py +0 -31
- glaip_sdk/cli/transcript/cache.py +0 -536
- glaip_sdk/cli/transcript/capture.py +0 -329
- glaip_sdk/cli/transcript/export.py +0 -38
- glaip_sdk/cli/transcript/history.py +0 -815
- glaip_sdk/cli/transcript/launcher.py +0 -77
- glaip_sdk/cli/transcript/viewer.py +0 -374
- glaip_sdk/cli/update_notifier.py +0 -290
- glaip_sdk/cli/utils.py +0 -263
- glaip_sdk/cli/validators.py +0 -238
- glaip_sdk/client/__init__.py +0 -11
- glaip_sdk/client/_agent_payloads.py +0 -520
- glaip_sdk/client/agent_runs.py +0 -147
- glaip_sdk/client/agents.py +0 -1335
- glaip_sdk/client/base.py +0 -502
- glaip_sdk/client/main.py +0 -249
- glaip_sdk/client/mcps.py +0 -370
- glaip_sdk/client/run_rendering.py +0 -700
- glaip_sdk/client/shared.py +0 -21
- glaip_sdk/client/tools.py +0 -661
- glaip_sdk/client/validators.py +0 -198
- glaip_sdk/config/constants.py +0 -52
- glaip_sdk/mcps/__init__.py +0 -21
- glaip_sdk/mcps/base.py +0 -345
- glaip_sdk/models/__init__.py +0 -90
- glaip_sdk/models/agent.py +0 -47
- glaip_sdk/models/agent_runs.py +0 -116
- glaip_sdk/models/common.py +0 -42
- glaip_sdk/models/mcp.py +0 -33
- glaip_sdk/models/tool.py +0 -33
- glaip_sdk/payload_schemas/__init__.py +0 -7
- glaip_sdk/payload_schemas/agent.py +0 -85
- glaip_sdk/registry/__init__.py +0 -55
- glaip_sdk/registry/agent.py +0 -164
- glaip_sdk/registry/base.py +0 -139
- glaip_sdk/registry/mcp.py +0 -253
- glaip_sdk/registry/tool.py +0 -232
- glaip_sdk/runner/__init__.py +0 -59
- glaip_sdk/runner/base.py +0 -84
- glaip_sdk/runner/deps.py +0 -115
- glaip_sdk/runner/langgraph.py +0 -782
- glaip_sdk/runner/mcp_adapter/__init__.py +0 -13
- glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +0 -43
- glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +0 -257
- glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +0 -95
- glaip_sdk/runner/tool_adapter/__init__.py +0 -18
- glaip_sdk/runner/tool_adapter/base_tool_adapter.py +0 -44
- glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +0 -219
- glaip_sdk/tools/__init__.py +0 -22
- glaip_sdk/tools/base.py +0 -435
- glaip_sdk/utils/__init__.py +0 -86
- glaip_sdk/utils/a2a/__init__.py +0 -34
- glaip_sdk/utils/a2a/event_processor.py +0 -188
- glaip_sdk/utils/agent_config.py +0 -194
- glaip_sdk/utils/bundler.py +0 -267
- glaip_sdk/utils/client.py +0 -111
- glaip_sdk/utils/client_utils.py +0 -486
- glaip_sdk/utils/datetime_helpers.py +0 -58
- glaip_sdk/utils/discovery.py +0 -78
- glaip_sdk/utils/display.py +0 -135
- glaip_sdk/utils/export.py +0 -143
- glaip_sdk/utils/general.py +0 -61
- glaip_sdk/utils/import_export.py +0 -168
- glaip_sdk/utils/import_resolver.py +0 -492
- glaip_sdk/utils/instructions.py +0 -101
- glaip_sdk/utils/rendering/__init__.py +0 -115
- glaip_sdk/utils/rendering/formatting.py +0 -264
- glaip_sdk/utils/rendering/layout/__init__.py +0 -64
- glaip_sdk/utils/rendering/layout/panels.py +0 -156
- glaip_sdk/utils/rendering/layout/progress.py +0 -202
- glaip_sdk/utils/rendering/layout/summary.py +0 -74
- glaip_sdk/utils/rendering/layout/transcript.py +0 -606
- glaip_sdk/utils/rendering/models.py +0 -85
- glaip_sdk/utils/rendering/renderer/__init__.py +0 -55
- glaip_sdk/utils/rendering/renderer/base.py +0 -1024
- glaip_sdk/utils/rendering/renderer/config.py +0 -27
- glaip_sdk/utils/rendering/renderer/console.py +0 -55
- glaip_sdk/utils/rendering/renderer/debug.py +0 -178
- glaip_sdk/utils/rendering/renderer/factory.py +0 -138
- glaip_sdk/utils/rendering/renderer/stream.py +0 -202
- glaip_sdk/utils/rendering/renderer/summary_window.py +0 -79
- glaip_sdk/utils/rendering/renderer/thinking.py +0 -273
- glaip_sdk/utils/rendering/renderer/toggle.py +0 -182
- glaip_sdk/utils/rendering/renderer/tool_panels.py +0 -442
- glaip_sdk/utils/rendering/renderer/transcript_mode.py +0 -162
- glaip_sdk/utils/rendering/state.py +0 -204
- glaip_sdk/utils/rendering/step_tree_state.py +0 -100
- glaip_sdk/utils/rendering/steps/__init__.py +0 -34
- glaip_sdk/utils/rendering/steps/event_processor.py +0 -778
- glaip_sdk/utils/rendering/steps/format.py +0 -176
- glaip_sdk/utils/rendering/steps/manager.py +0 -387
- glaip_sdk/utils/rendering/timing.py +0 -36
- glaip_sdk/utils/rendering/viewer/__init__.py +0 -21
- glaip_sdk/utils/rendering/viewer/presenter.py +0 -184
- glaip_sdk/utils/resource_refs.py +0 -195
- glaip_sdk/utils/run_renderer.py +0 -41
- glaip_sdk/utils/runtime_config.py +0 -425
- glaip_sdk/utils/serialization.py +0 -424
- glaip_sdk/utils/sync.py +0 -142
- glaip_sdk/utils/tool_detection.py +0 -33
- glaip_sdk/utils/validation.py +0 -264
- glaip_sdk-0.6.12.dist-info/RECORD +0 -159
- glaip_sdk-0.6.12.dist-info/entry_points.txt +0 -3
glaip_sdk/cli/commands/update.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"""Update command for upgrading the glaip-sdk package.
|
|
2
|
-
|
|
3
|
-
Author:
|
|
4
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import subprocess
|
|
10
|
-
import sys
|
|
11
|
-
from collections.abc import Sequence
|
|
12
|
-
|
|
13
|
-
import click
|
|
14
|
-
from rich.console import Console
|
|
15
|
-
|
|
16
|
-
from glaip_sdk.branding import ACCENT_STYLE, ERROR_STYLE, INFO_STYLE, SUCCESS_STYLE
|
|
17
|
-
|
|
18
|
-
PACKAGE_NAME = "glaip-sdk"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _build_upgrade_command(include_prerelease: bool) -> Sequence[str]:
|
|
22
|
-
"""Return the pip command used to upgrade the SDK."""
|
|
23
|
-
command = [
|
|
24
|
-
sys.executable,
|
|
25
|
-
"-m",
|
|
26
|
-
"pip",
|
|
27
|
-
"install",
|
|
28
|
-
"--upgrade",
|
|
29
|
-
PACKAGE_NAME,
|
|
30
|
-
]
|
|
31
|
-
if include_prerelease:
|
|
32
|
-
command.append("--pre")
|
|
33
|
-
return command
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@click.command(name="update")
|
|
37
|
-
@click.option(
|
|
38
|
-
"--pre",
|
|
39
|
-
"include_prerelease",
|
|
40
|
-
is_flag=True,
|
|
41
|
-
help="Include pre-release versions when upgrading.",
|
|
42
|
-
)
|
|
43
|
-
def update_command(include_prerelease: bool) -> None:
|
|
44
|
-
"""Upgrade the glaip-sdk package using pip."""
|
|
45
|
-
console = Console()
|
|
46
|
-
upgrade_cmd = _build_upgrade_command(include_prerelease)
|
|
47
|
-
console.print(f"[{ACCENT_STYLE}]Upgrading {PACKAGE_NAME} using[/] [{INFO_STYLE}]{' '.join(upgrade_cmd)}[/]")
|
|
48
|
-
|
|
49
|
-
try:
|
|
50
|
-
subprocess.run(upgrade_cmd, check=True)
|
|
51
|
-
except FileNotFoundError as exc:
|
|
52
|
-
raise click.ClickException(
|
|
53
|
-
"Unable to locate Python executable to run pip. Please ensure Python is installed and try again."
|
|
54
|
-
) from exc
|
|
55
|
-
except subprocess.CalledProcessError as exc:
|
|
56
|
-
console.print(
|
|
57
|
-
f"[{ERROR_STYLE}]Automatic upgrade failed.[/] Please run `pip install -U {PACKAGE_NAME}` manually."
|
|
58
|
-
)
|
|
59
|
-
raise click.ClickException("Automatic upgrade failed.") from exc
|
|
60
|
-
|
|
61
|
-
console.print(f"[{SUCCESS_STYLE}]✅ {PACKAGE_NAME} upgraded successfully.[/]")
|
glaip_sdk/cli/config.py
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
"""Configuration management utilities.
|
|
2
|
-
|
|
3
|
-
Authors:
|
|
4
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
from copy import deepcopy
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from typing import Any
|
|
11
|
-
|
|
12
|
-
import yaml
|
|
13
|
-
|
|
14
|
-
_ENV_CONFIG_DIR = os.getenv("AIP_CONFIG_DIR")
|
|
15
|
-
# Detect pytest environment: check for pytest markers or test session
|
|
16
|
-
# This provides automatic test isolation even if conftest.py doesn't set AIP_CONFIG_DIR
|
|
17
|
-
# Note: conftest.py sets AIP_CONFIG_DIR before imports, which takes precedence
|
|
18
|
-
_TEST_ENV = os.getenv("PYTEST_CURRENT_TEST") or os.getenv("PYTEST_XDIST_WORKER") or os.getenv("_PYTEST_RAISE")
|
|
19
|
-
|
|
20
|
-
if _ENV_CONFIG_DIR:
|
|
21
|
-
# Explicit override via environment variable (highest priority)
|
|
22
|
-
# This is set by conftest.py before imports, ensuring test isolation
|
|
23
|
-
CONFIG_DIR = Path(_ENV_CONFIG_DIR)
|
|
24
|
-
elif _TEST_ENV:
|
|
25
|
-
# Isolate test runs (including xdist workers) from the real user config directory
|
|
26
|
-
# Use a per-process unique temp directory to avoid conflicts in parallel test runs
|
|
27
|
-
import tempfile
|
|
28
|
-
import uuid
|
|
29
|
-
|
|
30
|
-
# Create a unique temp dir per test process to avoid conflicts
|
|
31
|
-
temp_base = Path(tempfile.gettempdir())
|
|
32
|
-
test_config_dir = temp_base / f"aip-test-config-{os.getpid()}-{uuid.uuid4().hex[:8]}"
|
|
33
|
-
CONFIG_DIR = test_config_dir
|
|
34
|
-
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
35
|
-
else: # pragma: no cover - default path used outside test runs
|
|
36
|
-
CONFIG_DIR = Path.home() / ".aip"
|
|
37
|
-
|
|
38
|
-
CONFIG_FILE = CONFIG_DIR / "config.yaml"
|
|
39
|
-
_ALLOWED_KEYS = {
|
|
40
|
-
"api_url",
|
|
41
|
-
"api_key",
|
|
42
|
-
"timeout",
|
|
43
|
-
"history_default_limit",
|
|
44
|
-
}
|
|
45
|
-
# Keys that must be preserved for multi-account support
|
|
46
|
-
_PRESERVE_KEYS = {
|
|
47
|
-
"version",
|
|
48
|
-
"active_account",
|
|
49
|
-
"accounts",
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def _sanitize_config(data: dict[str, Any] | None) -> dict[str, Any]:
|
|
54
|
-
"""Return config filtered to allowed keys only, preserving multi-account keys."""
|
|
55
|
-
if not data:
|
|
56
|
-
return {}
|
|
57
|
-
result: dict[str, Any] = {}
|
|
58
|
-
# Preserve multi-account structure (defensively copy to avoid callers mutating source)
|
|
59
|
-
for key in _PRESERVE_KEYS:
|
|
60
|
-
if key in data:
|
|
61
|
-
result[key] = deepcopy(data[key])
|
|
62
|
-
# Add allowed legacy keys (copied to avoid side effects)
|
|
63
|
-
for key in _ALLOWED_KEYS:
|
|
64
|
-
if key in data:
|
|
65
|
-
result[key] = deepcopy(data[key])
|
|
66
|
-
return result
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def load_config() -> dict[str, Any]:
|
|
70
|
-
"""Load configuration from file."""
|
|
71
|
-
if not CONFIG_FILE.exists():
|
|
72
|
-
return {}
|
|
73
|
-
|
|
74
|
-
try:
|
|
75
|
-
with open(CONFIG_FILE) as f:
|
|
76
|
-
loaded = yaml.safe_load(f) or {}
|
|
77
|
-
return _sanitize_config(loaded)
|
|
78
|
-
except yaml.YAMLError:
|
|
79
|
-
return {}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def save_config(config: dict[str, Any]) -> None:
|
|
83
|
-
"""Save configuration to file."""
|
|
84
|
-
CONFIG_DIR.mkdir(exist_ok=True)
|
|
85
|
-
|
|
86
|
-
sanitized = _sanitize_config(config)
|
|
87
|
-
|
|
88
|
-
with open(CONFIG_FILE, "w") as f:
|
|
89
|
-
yaml.dump(sanitized, f, default_flow_style=False)
|
|
90
|
-
|
|
91
|
-
# Set secure file permissions
|
|
92
|
-
try:
|
|
93
|
-
os.chmod(CONFIG_FILE, 0o600)
|
|
94
|
-
except OSError: # pragma: no cover - permission errors are expected in some environments
|
|
95
|
-
pass
|
glaip_sdk/cli/constants.py
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
"""CLI-specific constants for glaip-sdk.
|
|
2
|
-
|
|
3
|
-
Authors:
|
|
4
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
# Minimum length that forces multiline YAML strings to be rendered using the literal
|
|
8
|
-
# block style. This prevents long prompts and instructions from being inlined.
|
|
9
|
-
LITERAL_STRING_THRESHOLD = 200
|
|
10
|
-
|
|
11
|
-
# Masking configuration
|
|
12
|
-
MASKING_ENABLED = True
|
|
13
|
-
MASK_SENSITIVE_FIELDS = {
|
|
14
|
-
"api_key",
|
|
15
|
-
"apikey",
|
|
16
|
-
"token",
|
|
17
|
-
"access_token",
|
|
18
|
-
"secret",
|
|
19
|
-
"client_secret",
|
|
20
|
-
"password",
|
|
21
|
-
"private_key",
|
|
22
|
-
"bearer",
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
# Table + pager behaviour
|
|
26
|
-
TABLE_SORT_ENABLED = True
|
|
27
|
-
PAGER_MODE = "auto" # valid values: "auto", "on", "off"
|
|
28
|
-
PAGER_WRAP_LINES = False
|
|
29
|
-
PAGER_HEADER_ENABLED = True
|
|
30
|
-
|
|
31
|
-
# Update notification toggle
|
|
32
|
-
UPDATE_CHECK_ENABLED = True
|
|
33
|
-
|
|
34
|
-
# Agent instruction preview defaults
|
|
35
|
-
DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT = 800
|
|
36
|
-
|
|
37
|
-
# Remote runs defaults
|
|
38
|
-
DEFAULT_REMOTE_RUNS_PAGE_LIMIT = 20
|
glaip_sdk/cli/context.py
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
"""Context-related helpers for the glaip CLI.
|
|
2
|
-
|
|
3
|
-
Authors:
|
|
4
|
-
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from collections.abc import Callable
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
from typing import Any
|
|
12
|
-
|
|
13
|
-
import click
|
|
14
|
-
|
|
15
|
-
__all__ = [
|
|
16
|
-
"get_ctx_value",
|
|
17
|
-
"_get_view",
|
|
18
|
-
"_set_view",
|
|
19
|
-
"_set_json",
|
|
20
|
-
"output_flags",
|
|
21
|
-
"detect_export_format",
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def get_ctx_value(ctx: Any, key: str, default: Any = None) -> Any:
|
|
26
|
-
"""Safely resolve a value from a click context object.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
ctx: Click context object to extract value from
|
|
30
|
-
key: Key to retrieve from the context
|
|
31
|
-
default: Default value if key is not found
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
The value associated with the key, or the default if not found
|
|
35
|
-
"""
|
|
36
|
-
if ctx is None:
|
|
37
|
-
return default
|
|
38
|
-
|
|
39
|
-
obj = getattr(ctx, "obj", None)
|
|
40
|
-
if obj is None:
|
|
41
|
-
return default
|
|
42
|
-
|
|
43
|
-
if isinstance(obj, dict):
|
|
44
|
-
return obj.get(key, default)
|
|
45
|
-
|
|
46
|
-
getter = getattr(obj, "get", None)
|
|
47
|
-
if callable(getter):
|
|
48
|
-
try:
|
|
49
|
-
return getter(key, default)
|
|
50
|
-
except TypeError:
|
|
51
|
-
return default
|
|
52
|
-
|
|
53
|
-
return getattr(obj, key, default) if hasattr(obj, key) else default
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _get_view(ctx: Any) -> str:
|
|
57
|
-
"""Resolve the active view preference from context.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
ctx: Click context object containing view preferences
|
|
61
|
-
|
|
62
|
-
Returns:
|
|
63
|
-
The view format string (rich, plain, json, md), defaults to 'rich'
|
|
64
|
-
"""
|
|
65
|
-
view = get_ctx_value(ctx, "view")
|
|
66
|
-
if view:
|
|
67
|
-
return view
|
|
68
|
-
|
|
69
|
-
fallback = get_ctx_value(ctx, "format")
|
|
70
|
-
return fallback or "rich"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _set_view(ctx: Any, _param: Any, value: str) -> None:
|
|
74
|
-
"""Click callback to persist the `--view/--output` option.
|
|
75
|
-
|
|
76
|
-
Args:
|
|
77
|
-
ctx: Click context object to store the view preference
|
|
78
|
-
_param: Click parameter object (unused)
|
|
79
|
-
value: The view format string to store
|
|
80
|
-
"""
|
|
81
|
-
if not value:
|
|
82
|
-
return
|
|
83
|
-
ctx.ensure_object(dict)
|
|
84
|
-
ctx.obj["view"] = value
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _set_json(ctx: Any, _param: Any, value: bool) -> None:
|
|
88
|
-
"""Click callback for the `--json` shorthand flag.
|
|
89
|
-
|
|
90
|
-
Args:
|
|
91
|
-
ctx: Click context object to store the view preference
|
|
92
|
-
_param: Click parameter object (unused)
|
|
93
|
-
value: Boolean flag indicating json mode
|
|
94
|
-
"""
|
|
95
|
-
if not value:
|
|
96
|
-
return
|
|
97
|
-
ctx.ensure_object(dict)
|
|
98
|
-
ctx.obj["view"] = "json"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def output_flags() -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
102
|
-
"""Decorator to add shared output flags (`--view`, `--json`) to commands.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
A decorator function that adds output format options to click commands
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
def decorator(f: Callable[..., Any]) -> Callable[..., Any]:
|
|
109
|
-
"""Apply output flags to a click command.
|
|
110
|
-
|
|
111
|
-
Args:
|
|
112
|
-
f: Click command function to decorate.
|
|
113
|
-
|
|
114
|
-
Returns:
|
|
115
|
-
Decorated command function.
|
|
116
|
-
"""
|
|
117
|
-
f = click.option(
|
|
118
|
-
"--json",
|
|
119
|
-
"json_mode",
|
|
120
|
-
is_flag=True,
|
|
121
|
-
expose_value=False,
|
|
122
|
-
help="Shortcut for --view json",
|
|
123
|
-
callback=_set_json,
|
|
124
|
-
)(f)
|
|
125
|
-
f = click.option(
|
|
126
|
-
"-o",
|
|
127
|
-
"--output",
|
|
128
|
-
"--view",
|
|
129
|
-
"view_opt",
|
|
130
|
-
type=click.Choice(["rich", "plain", "json", "md"]),
|
|
131
|
-
expose_value=False,
|
|
132
|
-
help="Output format",
|
|
133
|
-
callback=_set_view,
|
|
134
|
-
)(f)
|
|
135
|
-
return f
|
|
136
|
-
|
|
137
|
-
return decorator
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def detect_export_format(file_path: str | Path) -> str:
|
|
141
|
-
"""Detect the export format from the file extension.
|
|
142
|
-
|
|
143
|
-
Args:
|
|
144
|
-
file_path: Path to the file to analyze
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
The format string ('yaml' or 'json') based on file extension
|
|
148
|
-
"""
|
|
149
|
-
path = Path(file_path)
|
|
150
|
-
return "yaml" if path.suffix.lower() in {".yaml", ".yml"} else "json"
|
glaip_sdk/cli/core/__init__.py
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"""CLI core modules for glaip-sdk.
|
|
2
|
-
|
|
3
|
-
This package contains focused modules extracted from the monolithic cli/utils.py:
|
|
4
|
-
- context: Click context helpers, config loading, credential resolution
|
|
5
|
-
- prompting: prompt_toolkit + questionary wrappers, validators
|
|
6
|
-
- rendering: Rich console helpers, viewer launchers, renderer builders
|
|
7
|
-
- output: Table/console output utilities, list rendering
|
|
8
|
-
|
|
9
|
-
Authors:
|
|
10
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
11
|
-
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
12
|
-
""" # pylint: disable=duplicate-code
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
# Re-export all public APIs from submodules for convenience
|
|
17
|
-
from glaip_sdk.cli.core.context import (
|
|
18
|
-
bind_slash_session_context,
|
|
19
|
-
get_client,
|
|
20
|
-
handle_best_effort_check,
|
|
21
|
-
restore_slash_session_context,
|
|
22
|
-
)
|
|
23
|
-
from glaip_sdk.cli.core.output import (
|
|
24
|
-
coerce_to_row,
|
|
25
|
-
detect_export_format,
|
|
26
|
-
fetch_resource_for_export,
|
|
27
|
-
format_datetime_fields,
|
|
28
|
-
format_size,
|
|
29
|
-
handle_resource_export,
|
|
30
|
-
output_list,
|
|
31
|
-
output_result,
|
|
32
|
-
parse_json_line,
|
|
33
|
-
resolve_resource,
|
|
34
|
-
handle_ambiguous_resource,
|
|
35
|
-
sdk_version,
|
|
36
|
-
)
|
|
37
|
-
from glaip_sdk.cli.core.prompting import (
|
|
38
|
-
_fuzzy_pick_for_resources,
|
|
39
|
-
prompt_export_choice_questionary,
|
|
40
|
-
questionary_safe_ask,
|
|
41
|
-
)
|
|
42
|
-
from glaip_sdk.cli.core.rendering import (
|
|
43
|
-
build_renderer,
|
|
44
|
-
spinner_context,
|
|
45
|
-
stop_spinner,
|
|
46
|
-
update_spinner,
|
|
47
|
-
with_client_and_spinner,
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
__all__ = [
|
|
51
|
-
# Context
|
|
52
|
-
"bind_slash_session_context",
|
|
53
|
-
"get_client",
|
|
54
|
-
"handle_best_effort_check",
|
|
55
|
-
"restore_slash_session_context",
|
|
56
|
-
# Prompting
|
|
57
|
-
"_fuzzy_pick_for_resources",
|
|
58
|
-
"prompt_export_choice_questionary",
|
|
59
|
-
"questionary_safe_ask",
|
|
60
|
-
# Rendering
|
|
61
|
-
"build_renderer",
|
|
62
|
-
"spinner_context",
|
|
63
|
-
"stop_spinner",
|
|
64
|
-
"update_spinner",
|
|
65
|
-
"with_client_and_spinner",
|
|
66
|
-
# Output
|
|
67
|
-
"coerce_to_row",
|
|
68
|
-
"detect_export_format",
|
|
69
|
-
"fetch_resource_for_export",
|
|
70
|
-
"format_datetime_fields",
|
|
71
|
-
"format_size",
|
|
72
|
-
"handle_resource_export",
|
|
73
|
-
"output_list",
|
|
74
|
-
"output_result",
|
|
75
|
-
"parse_json_line",
|
|
76
|
-
"resolve_resource",
|
|
77
|
-
"handle_ambiguous_resource",
|
|
78
|
-
"sdk_version",
|
|
79
|
-
]
|
glaip_sdk/cli/core/context.py
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
"""CLI context helpers, config loading, and credential resolution.
|
|
2
|
-
|
|
3
|
-
Authors:
|
|
4
|
-
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
|
-
Putu Ravindra Wiguna (putu.r.wiguna@gdplabs.id)
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import importlib
|
|
11
|
-
import os
|
|
12
|
-
from collections.abc import Mapping
|
|
13
|
-
from contextlib import contextmanager
|
|
14
|
-
from typing import TYPE_CHECKING, Any, cast
|
|
15
|
-
|
|
16
|
-
import click
|
|
17
|
-
|
|
18
|
-
from glaip_sdk.cli.config import load_config
|
|
19
|
-
from glaip_sdk.cli.hints import command_hint
|
|
20
|
-
|
|
21
|
-
if TYPE_CHECKING: # pragma: no cover - import-only during type checking
|
|
22
|
-
from glaip_sdk import Client
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@contextmanager
|
|
26
|
-
def bind_slash_session_context(ctx: Any, session: Any) -> Any:
|
|
27
|
-
"""Temporarily attach a slash session to the Click context.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
ctx: Click context object.
|
|
31
|
-
session: SlashSession instance to bind.
|
|
32
|
-
|
|
33
|
-
Yields:
|
|
34
|
-
None - context manager for use in with statement.
|
|
35
|
-
"""
|
|
36
|
-
ctx_obj = getattr(ctx, "obj", None)
|
|
37
|
-
has_context = isinstance(ctx_obj, dict)
|
|
38
|
-
previous_session = ctx_obj.get("_slash_session") if has_context else None
|
|
39
|
-
if has_context:
|
|
40
|
-
ctx_obj["_slash_session"] = session
|
|
41
|
-
try:
|
|
42
|
-
yield
|
|
43
|
-
finally:
|
|
44
|
-
if has_context:
|
|
45
|
-
if previous_session is None:
|
|
46
|
-
ctx_obj.pop("_slash_session", None)
|
|
47
|
-
else:
|
|
48
|
-
ctx_obj["_slash_session"] = previous_session
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def restore_slash_session_context(ctx_obj: dict[str, Any], previous_session: Any | None) -> None:
|
|
52
|
-
"""Restore slash session context after operation.
|
|
53
|
-
|
|
54
|
-
Args:
|
|
55
|
-
ctx_obj: Click context obj dictionary.
|
|
56
|
-
previous_session: Previous session to restore, or None to remove.
|
|
57
|
-
"""
|
|
58
|
-
if previous_session is None:
|
|
59
|
-
ctx_obj.pop("_slash_session", None)
|
|
60
|
-
else:
|
|
61
|
-
ctx_obj["_slash_session"] = previous_session
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def handle_best_effort_check(
|
|
65
|
-
check_func: Any,
|
|
66
|
-
) -> None:
|
|
67
|
-
"""Handle best-effort duplicate/existence checks with proper exception handling.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
check_func: Function that performs the check and raises ClickException if duplicate found.
|
|
71
|
-
"""
|
|
72
|
-
try:
|
|
73
|
-
check_func()
|
|
74
|
-
except click.ClickException:
|
|
75
|
-
raise
|
|
76
|
-
except Exception:
|
|
77
|
-
# Non-fatal: best-effort duplicate check
|
|
78
|
-
pass
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def get_client(ctx: Any) -> Client: # pragma: no cover
|
|
82
|
-
"""Get configured client from context and account store (ctx > account)."""
|
|
83
|
-
# Import here to avoid circular import
|
|
84
|
-
from glaip_sdk.cli.auth import resolve_credentials # noqa: PLC0415
|
|
85
|
-
|
|
86
|
-
module = importlib.import_module("glaip_sdk")
|
|
87
|
-
client_class = cast("type[Client]", module.Client)
|
|
88
|
-
context_config_obj = getattr(ctx, "obj", None)
|
|
89
|
-
context_config = context_config_obj if isinstance(context_config_obj, Mapping) else {}
|
|
90
|
-
|
|
91
|
-
account_name = context_config.get("account_name")
|
|
92
|
-
api_url, api_key, _ = resolve_credentials(
|
|
93
|
-
account_name=account_name,
|
|
94
|
-
api_url=context_config.get("api_url"),
|
|
95
|
-
api_key=context_config.get("api_key"),
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
if not api_url or not api_key:
|
|
99
|
-
configure_hint = command_hint("accounts add", slash_command="login", ctx=ctx)
|
|
100
|
-
actions: list[str] = []
|
|
101
|
-
if configure_hint:
|
|
102
|
-
actions.append(f"Run `{configure_hint}` to add an account profile")
|
|
103
|
-
else:
|
|
104
|
-
actions.append("add an account with 'aip accounts add'")
|
|
105
|
-
raise click.ClickException(f"Missing api_url/api_key. {' or '.join(actions)}.")
|
|
106
|
-
|
|
107
|
-
# Get timeout from context or config
|
|
108
|
-
timeout = context_config.get("timeout")
|
|
109
|
-
if timeout is None:
|
|
110
|
-
raw_timeout = os.getenv("AIP_TIMEOUT", "0") or "0"
|
|
111
|
-
try:
|
|
112
|
-
timeout = float(raw_timeout) if raw_timeout != "0" else None
|
|
113
|
-
except ValueError:
|
|
114
|
-
timeout = None
|
|
115
|
-
if timeout is None:
|
|
116
|
-
# Fallback to legacy config
|
|
117
|
-
file_config = load_config() or {}
|
|
118
|
-
timeout = file_config.get("timeout")
|
|
119
|
-
|
|
120
|
-
return client_class(
|
|
121
|
-
api_url=api_url,
|
|
122
|
-
api_key=api_key,
|
|
123
|
-
timeout=float(timeout or 30.0),
|
|
124
|
-
)
|