systemlink-cli 1.5.2__tar.gz → 1.6.1__tar.gz
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.
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/PKG-INFO +3 -1
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/pyproject.toml +3 -1
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/_version.py +1 -1
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/cli_utils.py +6 -42
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/config_click.py +23 -45
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/main.py +46 -37
- systemlink_cli-1.6.1/slcli/rich_output.py +435 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/system_click.py +16 -14
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/table_utils.py +7 -53
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/tag_click.py +2 -4
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/user_click.py +12 -34
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/utils.py +26 -85
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/workspace_click.py +36 -33
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/LICENSE +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/dff-editor/editor.js +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/dff-editor/index.html +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/__init__.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/__main__.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/asset_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/cli_formatters.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/comment_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/completion_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/config.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/dff_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/dff_decorators.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/example_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/example_loader.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/example_provisioner.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/README.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/_schema/schema-v1.0.json +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/demo-complete-workflow/README.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/demo-complete-workflow/config.yaml +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/demo-test-plans/README.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/demo-test-plans/config.yaml +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/exercise-5-1-parametric-insights/README.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/exercise-5-1-parametric-insights/config.yaml +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/exercise-7-1-test-plans/README.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/exercise-7-1-test-plans/config.yaml +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/spec-compliance-notebooks/README.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/spec-compliance-notebooks/config.yaml +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/feed_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/file_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/function_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/function_templates.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/mcp_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/mcp_server.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/notebook_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/platform.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/policy_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/policy_utils.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/profiles.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/response_handlers.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/routine_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skill_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/slcli/SKILL.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/slcli/references/analysis-recipes.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/slcli/references/filtering.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/systemlink-webapp/SKILL.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/systemlink-webapp/references/deployment.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/systemlink-webapp/references/layout-patterns.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/systemlink-webapp/references/nimble-angular.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/skills/systemlink-webapp/references/systemlink-services.md +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/ssl_trust.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/templates_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/testmonitor_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/universal_handlers.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/web_editor.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/webapp_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/workflow_preview.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/workflows_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/workitem_click.py +0 -0
- {systemlink_cli-1.5.2 → systemlink_cli-1.6.1}/slcli/workspace_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: systemlink-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.6.1
|
|
4
4
|
Summary: SystemLink Integrator CLI - cross-platform CLI for SystemLink workflows and templates.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Fred Visser
|
|
@@ -15,6 +15,8 @@ Requires-Dist: keyring (>=25.6.0,<26.0.0)
|
|
|
15
15
|
Requires-Dist: pyyaml (>=6.0.3,<7.0.0)
|
|
16
16
|
Requires-Dist: questionary (>=2.1.1,<3.0.0)
|
|
17
17
|
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
18
|
+
Requires-Dist: rich (>=13.7,<15)
|
|
19
|
+
Requires-Dist: rich-click (>=1.8,<2)
|
|
18
20
|
Requires-Dist: tabulate (>=0.10.0,<0.11.0)
|
|
19
21
|
Requires-Dist: truststore (>=0.9,<0.11)
|
|
20
22
|
Requires-Dist: watchdog (>=6.0.0,<7.0.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "systemlink-cli"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.6.1"
|
|
4
4
|
description = "SystemLink Integrator CLI - cross-platform CLI for SystemLink workflows and templates."
|
|
5
5
|
authors = ["Fred Visser <fred.visser@emerson.com>"]
|
|
6
6
|
packages = [{ include = "slcli" }]
|
|
@@ -35,6 +35,8 @@ truststore = ">=0.9,<0.11"
|
|
|
35
35
|
watchdog = "^6.0.0"
|
|
36
36
|
pyyaml = "^6.0.3"
|
|
37
37
|
questionary = "^2.1.1"
|
|
38
|
+
rich = ">=13.7,<15"
|
|
39
|
+
rich-click = ">=1.8,<2"
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
[tool.poetry.group.dev.dependencies]
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"""Common utility functions for all CLI commands."""
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
import questionary
|
|
8
8
|
import requests
|
|
9
9
|
|
|
10
|
+
from .rich_output import print_json, render_table
|
|
10
11
|
from .utils import ExitCodes, handle_api_error
|
|
11
12
|
|
|
12
13
|
|
|
@@ -368,9 +369,7 @@ def paginate_list_output(
|
|
|
368
369
|
|
|
369
370
|
# For JSON format, show all results at once (no pagination)
|
|
370
371
|
if format_output.lower() == "json":
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
click.echo(json.dumps(items, indent=2))
|
|
372
|
+
print_json(items)
|
|
374
373
|
return
|
|
375
374
|
|
|
376
375
|
# Table format with pagination
|
|
@@ -456,49 +455,14 @@ def _output_formatted_page(
|
|
|
456
455
|
if not items:
|
|
457
456
|
return
|
|
458
457
|
|
|
459
|
-
# Table format with box-drawing characters (without footer)
|
|
460
458
|
if len(headers) != len(column_widths):
|
|
461
459
|
raise ValueError("Headers and column_widths must have the same length")
|
|
462
460
|
|
|
463
|
-
|
|
464
|
-
border_chars = ["┌"] + [("─" * (w + 2)) for w in column_widths]
|
|
465
|
-
border_line = border_chars[0] + border_chars[1]
|
|
466
|
-
for part in border_chars[2:]:
|
|
467
|
-
border_line += "┬" + part
|
|
468
|
-
border_line += "┐"
|
|
469
|
-
click.echo(border_line)
|
|
470
|
-
|
|
471
|
-
# Header row
|
|
472
|
-
header_parts = ["│"]
|
|
473
|
-
for header, width in zip(headers, column_widths):
|
|
474
|
-
header_parts.append(f" {header:<{width}} │")
|
|
475
|
-
click.echo("".join(header_parts))
|
|
476
|
-
|
|
477
|
-
# Middle border
|
|
478
|
-
border_chars = ["├"] + [("─" * (w + 2)) for w in column_widths]
|
|
479
|
-
border_line = border_chars[0] + border_chars[1]
|
|
480
|
-
for part in border_chars[2:]:
|
|
481
|
-
border_line += "┼" + part
|
|
482
|
-
border_line += "┤"
|
|
483
|
-
click.echo(border_line)
|
|
484
|
-
|
|
485
|
-
# Data rows
|
|
461
|
+
rows = []
|
|
486
462
|
for item in items:
|
|
487
463
|
row_data = row_formatter_func(item)
|
|
488
464
|
if len(row_data) != len(column_widths):
|
|
489
465
|
raise ValueError("Row data must match column count")
|
|
466
|
+
rows.append(row_data)
|
|
490
467
|
|
|
491
|
-
|
|
492
|
-
for value, width in zip(row_data, column_widths):
|
|
493
|
-
# Truncate if necessary
|
|
494
|
-
str_value = str(value or "")[:width]
|
|
495
|
-
row_parts.append(f" {str_value:<{width}} │")
|
|
496
|
-
click.echo("".join(row_parts))
|
|
497
|
-
|
|
498
|
-
# Bottom border
|
|
499
|
-
border_chars = ["└"] + [("─" * (w + 2)) for w in column_widths]
|
|
500
|
-
border_line = border_chars[0] + border_chars[1]
|
|
501
|
-
for part in border_chars[2:]:
|
|
502
|
-
border_line += "┴" + part
|
|
503
|
-
border_line += "┘"
|
|
504
|
-
click.echo(border_line)
|
|
468
|
+
render_table(headers, column_widths, rows, show_total=False)
|
|
@@ -14,6 +14,7 @@ from .platform import (
|
|
|
14
14
|
check_service_status,
|
|
15
15
|
)
|
|
16
16
|
from .profiles import ProfileConfig, Profile, check_config_file_permissions
|
|
17
|
+
from .rich_output import render_table
|
|
17
18
|
from .table_utils import output_formatted_list
|
|
18
19
|
from .utils import ExitCodes
|
|
19
20
|
|
|
@@ -337,65 +338,42 @@ def register_config_commands(cli: Any) -> None:
|
|
|
337
338
|
click.echo(json.dumps(data, indent=2))
|
|
338
339
|
return
|
|
339
340
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if cfg.current_profile:
|
|
346
|
-
click.echo(f"│ Current Profile: {cfg.current_profile:<42} │")
|
|
347
|
-
else:
|
|
348
|
-
click.echo("│ Current Profile: (none) │")
|
|
349
|
-
|
|
350
|
-
config_path_str = str(ProfileConfig.get_config_path())
|
|
351
|
-
if len(config_path_str) > 46:
|
|
352
|
-
config_path_str = config_path_str[:43] + "..."
|
|
353
|
-
click.echo(f"│ Config File: {config_path_str:<46} │")
|
|
341
|
+
rows = [
|
|
342
|
+
["Current Profile", cfg.current_profile or "(none)"],
|
|
343
|
+
["Config File", str(ProfileConfig.get_config_path())],
|
|
344
|
+
]
|
|
354
345
|
|
|
355
|
-
# Show current profile details
|
|
356
346
|
if cfg.current_profile and cfg.current_profile in cfg.profiles:
|
|
357
347
|
profile = cfg.profiles[cfg.current_profile]
|
|
358
|
-
|
|
348
|
+
rows.append(["Server", profile.server])
|
|
359
349
|
|
|
360
|
-
# Server
|
|
361
|
-
server_str = profile.server
|
|
362
|
-
if len(server_str) > 47:
|
|
363
|
-
server_str = server_str[:44] + "..."
|
|
364
|
-
click.echo(f"│ Server: {server_str:<51} │")
|
|
365
|
-
|
|
366
|
-
# Web URL
|
|
367
350
|
if profile.web_url:
|
|
368
|
-
|
|
369
|
-
if len(web_url_str) > 45:
|
|
370
|
-
web_url_str = web_url_str[:42] + "..."
|
|
371
|
-
click.echo(f"│ Web URL: {web_url_str:<50} │")
|
|
351
|
+
rows.append(["Web URL", profile.web_url])
|
|
372
352
|
|
|
373
|
-
# Platform
|
|
374
353
|
if profile.platform:
|
|
375
|
-
|
|
376
|
-
click.echo(f"│ Platform: {platform_str:<49} │")
|
|
354
|
+
rows.append(["Platform", profile.platform or "Unknown"])
|
|
377
355
|
|
|
378
|
-
# API Key (redacted)
|
|
379
356
|
if show_secrets:
|
|
380
|
-
|
|
357
|
+
api_key_display = profile.api_key
|
|
381
358
|
else:
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
359
|
+
api_key_display = (
|
|
360
|
+
"****" + profile.api_key[-4:] if len(profile.api_key) >= 4 else "****"
|
|
361
|
+
)
|
|
362
|
+
rows.append(["API Key", api_key_display])
|
|
386
363
|
|
|
387
|
-
# Workspace
|
|
388
364
|
if profile.workspace:
|
|
389
|
-
|
|
390
|
-
if len(workspace_str) > 45:
|
|
391
|
-
workspace_str = workspace_str[:42] + "..."
|
|
392
|
-
click.echo(f"│ Workspace: {workspace_str:<48} │")
|
|
365
|
+
rows.append(["Workspace", profile.workspace])
|
|
393
366
|
|
|
394
|
-
# Readonly
|
|
395
367
|
if profile.readonly:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
click.echo("
|
|
368
|
+
rows.append(["Readonly", "enabled"])
|
|
369
|
+
|
|
370
|
+
click.echo("slcli Configuration:")
|
|
371
|
+
render_table(
|
|
372
|
+
headers=["SETTING", "VALUE"],
|
|
373
|
+
column_widths=[18, 70],
|
|
374
|
+
rows=rows,
|
|
375
|
+
show_total=False,
|
|
376
|
+
)
|
|
399
377
|
|
|
400
378
|
# Check for permission warning
|
|
401
379
|
warning = check_config_file_permissions()
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
from types import ModuleType
|
|
5
6
|
from typing import Optional
|
|
6
7
|
|
|
7
|
-
import click
|
|
8
|
+
import click as base_click
|
|
8
9
|
import keyring
|
|
9
10
|
import questionary
|
|
10
11
|
import tomllib
|
|
@@ -25,6 +26,8 @@ from .platform import (
|
|
|
25
26
|
)
|
|
26
27
|
from .policy_click import register_policy_commands
|
|
27
28
|
from .profiles import set_profile_override
|
|
29
|
+
from .rich_output import install_rich_output
|
|
30
|
+
from .rich_output import render_table
|
|
28
31
|
from .routine_click import register_routine_commands
|
|
29
32
|
from .skill_click import register_skill_commands
|
|
30
33
|
from .ssl_trust import OS_TRUST_INJECTED, OS_TRUST_REASON
|
|
@@ -37,6 +40,14 @@ from .webapp_click import register_webapp_commands
|
|
|
37
40
|
from .workitem_click import register_workitem_commands
|
|
38
41
|
from .workspace_click import register_workspace_commands
|
|
39
42
|
|
|
43
|
+
click: ModuleType
|
|
44
|
+
try:
|
|
45
|
+
import rich_click as rich_click_module # type: ignore[import-not-found]
|
|
46
|
+
except ModuleNotFoundError:
|
|
47
|
+
click = base_click
|
|
48
|
+
else:
|
|
49
|
+
click = rich_click_module
|
|
50
|
+
|
|
40
51
|
|
|
41
52
|
def get_version() -> str:
|
|
42
53
|
"""Get version from _version.py (built binary) or pyproject.toml (development)."""
|
|
@@ -83,8 +94,10 @@ def get_ascii_art() -> str:
|
|
|
83
94
|
help="Use a specific profile for this command",
|
|
84
95
|
)
|
|
85
96
|
@click.pass_context
|
|
86
|
-
def cli(ctx:
|
|
97
|
+
def cli(ctx: base_click.Context, version: bool, profile: Optional[str]) -> None:
|
|
87
98
|
"""SystemLink CLI for managing SystemLink resources.""" # noqa: D403
|
|
99
|
+
install_rich_output()
|
|
100
|
+
|
|
88
101
|
if version:
|
|
89
102
|
click.echo(f"slcli version {get_version()}")
|
|
90
103
|
ctx.exit()
|
|
@@ -314,13 +327,7 @@ def info(format: str, skip_health: bool) -> None:
|
|
|
314
327
|
click.echo(json.dumps(platform_info, indent=2))
|
|
315
328
|
return
|
|
316
329
|
|
|
317
|
-
# Table format using box-drawing characters for key-value display.
|
|
318
|
-
# Note: This uses a custom layout rather than table_utils because table_utils
|
|
319
|
-
# is designed for list-style output (multiple uniform rows), while this command
|
|
320
|
-
# displays a single record with key-value pairs and feature availability.
|
|
321
|
-
# All text fields are truncated to prevent formatting issues with long values.
|
|
322
330
|
max_value_width = 45 # Maximum width for values before truncation
|
|
323
|
-
content_width = 61 # Total width inside the box
|
|
324
331
|
|
|
325
332
|
def truncate(value: str, max_len: int = max_value_width) -> str:
|
|
326
333
|
"""Truncate a string with ellipsis if it exceeds max length."""
|
|
@@ -328,11 +335,6 @@ def info(format: str, skip_health: bool) -> None:
|
|
|
328
335
|
return value[: max_len - 3] + "..."
|
|
329
336
|
return value
|
|
330
337
|
|
|
331
|
-
click.echo("\n┌" + "─" * content_width + "┐")
|
|
332
|
-
click.echo("│" + "SystemLink CLI Info".center(content_width) + "│")
|
|
333
|
-
click.echo("├" + "─" * content_width + "┤")
|
|
334
|
-
|
|
335
|
-
# Connection status
|
|
336
338
|
if not platform_info["logged_in"]:
|
|
337
339
|
status = "✗ Not logged in"
|
|
338
340
|
elif platform_info.get("server_reachable") is False:
|
|
@@ -341,32 +343,27 @@ def info(format: str, skip_health: bool) -> None:
|
|
|
341
343
|
status = "✗ API key unauthorized"
|
|
342
344
|
else:
|
|
343
345
|
status = "✓ Connected"
|
|
344
|
-
click.echo(f"│ Status: {status:<48}│")
|
|
345
346
|
|
|
346
|
-
# Profile information
|
|
347
347
|
profile_display = platform_info.get("active_profile_name", "None")
|
|
348
348
|
if platform_info.get("profile_count", 0) > 1:
|
|
349
349
|
profile_display = f"{profile_display} (1 of {platform_info['profile_count']})"
|
|
350
350
|
profile_display = truncate(profile_display)
|
|
351
|
-
click.echo(f"│ Profile: {profile_display:<48}│")
|
|
352
|
-
|
|
353
|
-
# Platform
|
|
354
351
|
platform_display = truncate(platform_info.get("platform_display", "Unknown"))
|
|
355
|
-
click.echo(f"│ Platform: {platform_display:<48}│")
|
|
356
|
-
|
|
357
|
-
# API URL
|
|
358
352
|
api_url = truncate(platform_info.get("api_url", "Not configured"))
|
|
359
|
-
click.echo(f"│ API URL: {api_url:<48}│")
|
|
360
|
-
|
|
361
|
-
# Web URL
|
|
362
353
|
web_url = truncate(platform_info.get("web_url", "Not configured"))
|
|
363
|
-
click.echo(f"│ Web URL: {web_url:<48}│")
|
|
364
354
|
|
|
365
|
-
|
|
355
|
+
info_rows = [
|
|
356
|
+
["Status", status],
|
|
357
|
+
["Profile", profile_display],
|
|
358
|
+
["Platform", platform_display],
|
|
359
|
+
["API URL", api_url],
|
|
360
|
+
["Web URL", web_url],
|
|
361
|
+
]
|
|
362
|
+
|
|
366
363
|
workspace = platform_info.get("active_profile_workspace")
|
|
367
364
|
if workspace:
|
|
368
365
|
workspace_display = truncate(workspace)
|
|
369
|
-
|
|
366
|
+
info_rows.append(["Workspace", workspace_display])
|
|
370
367
|
|
|
371
368
|
file_query_endpoint = platform_info.get("file_query_endpoint")
|
|
372
369
|
if file_query_endpoint:
|
|
@@ -375,15 +372,19 @@ def info(format: str, skip_health: bool) -> None:
|
|
|
375
372
|
else:
|
|
376
373
|
file_query_display = str(file_query_endpoint)
|
|
377
374
|
file_query_display = truncate(file_query_display)
|
|
378
|
-
|
|
375
|
+
info_rows.append(["File Query", file_query_display])
|
|
376
|
+
|
|
377
|
+
click.echo()
|
|
378
|
+
click.echo("SystemLink CLI Info:")
|
|
379
|
+
render_table(
|
|
380
|
+
headers=["SETTING", "VALUE"],
|
|
381
|
+
column_widths=[16, 48],
|
|
382
|
+
rows=info_rows,
|
|
383
|
+
show_total=False,
|
|
384
|
+
)
|
|
379
385
|
|
|
380
|
-
# Service Health section (only when services were checked)
|
|
381
386
|
services = platform_info.get("services")
|
|
382
387
|
if services:
|
|
383
|
-
click.echo("├" + "─" * content_width + "┤")
|
|
384
|
-
click.echo("│" + "Service Health".center(content_width) + "│")
|
|
385
|
-
click.echo("├" + "─" * content_width + "┤")
|
|
386
|
-
|
|
387
388
|
status_display = {
|
|
388
389
|
"ok": ("✓", "OK"),
|
|
389
390
|
"fallback": ("!", "Fallback (no Elasticsearch)"),
|
|
@@ -392,12 +393,20 @@ def info(format: str, skip_health: bool) -> None:
|
|
|
392
393
|
"error": ("✗", "Error"),
|
|
393
394
|
"unreachable": ("✗", "Unreachable"),
|
|
394
395
|
}
|
|
396
|
+
service_rows = []
|
|
395
397
|
for svc_name, svc_status in services.items():
|
|
396
398
|
icon, text = status_display.get(svc_status, ("?", svc_status))
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
399
|
+
service_rows.append([truncate(svc_name, 29), f"{icon} {text}"])
|
|
400
|
+
|
|
401
|
+
click.echo()
|
|
402
|
+
click.echo("Service Health:")
|
|
403
|
+
render_table(
|
|
404
|
+
headers=["SERVICE", "STATUS"],
|
|
405
|
+
column_widths=[26, 32],
|
|
406
|
+
rows=service_rows,
|
|
407
|
+
show_total=False,
|
|
408
|
+
)
|
|
409
|
+
click.echo()
|
|
401
410
|
|
|
402
411
|
|
|
403
412
|
register_completion_command(cli)
|