sv-cli 0.4.0__tar.gz → 0.5.0__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.
- {sv_cli-0.4.0 → sv_cli-0.5.0}/AGENT.md +1 -1
- {sv_cli-0.4.0 → sv_cli-0.5.0}/PKG-INFO +2 -2
- {sv_cli-0.4.0 → sv_cli-0.5.0}/pyproject.toml +1 -1
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/__init__.py +1 -1
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/adapters.py +1 -1
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/api_client.py +7 -2
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/executor.py +2 -1
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/main.py +14 -2
- {sv_cli-0.4.0 → sv_cli-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/.github/workflows/publish.yml +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/.github/workflows/release.yml +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/.github/workflows/test.yml +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/.gitignore +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/CHANGELOG.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/CODE_OF_CONDUCT.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/CONTRIBUTING.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/LICENSE +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/PULL_REQUEST_TEMPLATE.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/README.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/SECURITY.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/agent-usage.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/api-definition-format.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/authentication.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/commands.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/examples.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/installation.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/docs/troubleshooting.md +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/__init__.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/auth.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/better_keywords.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/call.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/config.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/content_quality.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/content_transformer.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/core_analysis.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/definitions.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/geo_audit.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/insight_igniter.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/marketplace_services.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/options.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/preliminary_audit.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/ranklens.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/seo_image.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/seo_mapping.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/seogpt.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/seogpt2.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/seogpt_compare.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/top_competitors.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/commands/topical_authority.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/config.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/definitions.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/errors.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/formatter.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/renderers/__init__.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/renderers/csv_renderer.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/renderers/json_renderer.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/renderers/markdown_renderer.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/renderers/table_renderer.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/renderers/text_renderer.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/resolver.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/schemas/__init__.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/schemas/api_response.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/schemas/config.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/schemas/tool_definition.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/tasks.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/src/sv_cli/utils.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/fixtures/api_root.json +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/fixtures/better_keywords_response.json +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/fixtures/ranklens_definitions.json +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/fixtures/seogpt2_definitions.json +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/fixtures/seogpt_definitions.json +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/test_config.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/test_definitions.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/test_executor.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/test_formatter.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/test_help_filtering.py +0 -0
- {sv_cli-0.4.0 → sv_cli-0.5.0}/tests/test_resolver.py +0 -0
|
@@ -87,7 +87,7 @@ seogpt: generate, raw
|
|
|
87
87
|
seogpt2: create-task, get-task-status, get-result, raw
|
|
88
88
|
seogpt-compare: create-task, get-task-status, get-result, raw
|
|
89
89
|
seo-mapping: create-task, get-task-status, get-result, raw
|
|
90
|
-
topical-authority: topics,
|
|
90
|
+
topical-authority: topics, raw
|
|
91
91
|
top-competitors: analyze, raw
|
|
92
92
|
marketplace-services: search, raw
|
|
93
93
|
content-quality: analyze, raw
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: sv-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Open-source, definition-driven command-line client for SV AI API tools.
|
|
5
5
|
Project-URL: Homepage, https://github.com/seovendorco/sv-cli
|
|
6
6
|
Project-URL: Issues, https://github.com/seovendorco/sv-cli/issues
|
|
@@ -242,7 +242,7 @@ TOOL_ADAPTERS: dict[str, ToolAdapter] = {
|
|
|
242
242
|
command="topical-authority",
|
|
243
243
|
aliases=("topical",),
|
|
244
244
|
default_action="topics",
|
|
245
|
-
actions=("topics", "
|
|
245
|
+
actions=("topics", "raw"),
|
|
246
246
|
field_aliases=COMMON_FIELD_ALIASES,
|
|
247
247
|
option_aliases={
|
|
248
248
|
"modes": ("topicmode", "topic_mode", "mode", "modes"),
|
|
@@ -24,9 +24,13 @@ class APIResponse:
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class APIClient:
|
|
27
|
-
def __init__(self, *, debug: bool = False, console: Console | None = None) -> None:
|
|
27
|
+
def __init__(self, *, debug: bool = False, console: Console | None = None, client_type: str | None = None) -> None:
|
|
28
28
|
self.debug = debug
|
|
29
29
|
self.console = console or Console(stderr=True)
|
|
30
|
+
# Identifies this process to the SV API as "cli" or "mcp" (X-SV-Client header)
|
|
31
|
+
# for usage tracking. None means the caller didn't specify one - the header is
|
|
32
|
+
# simply omitted, and the API buckets the call as generic "api" usage.
|
|
33
|
+
self.client_type = client_type
|
|
30
34
|
|
|
31
35
|
def request_tool(
|
|
32
36
|
self,
|
|
@@ -42,6 +46,7 @@ class APIClient:
|
|
|
42
46
|
final_payload["k"] = api_key
|
|
43
47
|
|
|
44
48
|
method = method.upper()
|
|
49
|
+
headers = {"X-SV-Client": self.client_type} if self.client_type else None
|
|
45
50
|
if self.debug:
|
|
46
51
|
parsed = urlparse(endpoint)
|
|
47
52
|
shown_path = parsed.path or endpoint
|
|
@@ -50,7 +55,7 @@ class APIClient:
|
|
|
50
55
|
|
|
51
56
|
started = time.perf_counter()
|
|
52
57
|
try:
|
|
53
|
-
with httpx.Client(timeout=timeout, follow_redirects=True) as client:
|
|
58
|
+
with httpx.Client(timeout=timeout, follow_redirects=True, headers=headers) as client:
|
|
54
59
|
if method == "GET":
|
|
55
60
|
response = client.get(endpoint, params=final_payload)
|
|
56
61
|
elif method in {"POST", "PUT", "PATCH"}:
|
|
@@ -120,6 +120,7 @@ def execute_tool(
|
|
|
120
120
|
raw_payload: dict[str, Any] | None = None,
|
|
121
121
|
method: str = "POST",
|
|
122
122
|
console: Console | None = None,
|
|
123
|
+
client_type: str | None = None,
|
|
123
124
|
) -> Any:
|
|
124
125
|
console = console or Console()
|
|
125
126
|
definitions = DefinitionsManager(runtime.base_url)
|
|
@@ -149,7 +150,7 @@ def execute_tool(
|
|
|
149
150
|
non_interactive=runtime.non_interactive,
|
|
150
151
|
)
|
|
151
152
|
|
|
152
|
-
client = APIClient(debug=runtime.debug, console=Console(stderr=True))
|
|
153
|
+
client = APIClient(debug=runtime.debug, console=Console(stderr=True), client_type=client_type)
|
|
153
154
|
response = client.request_tool(endpoint=str(endpoint), payload=payload, api_key=api_key, method=method)
|
|
154
155
|
data = response.data
|
|
155
156
|
|
|
@@ -228,6 +228,7 @@ def run_tool_action(
|
|
|
228
228
|
wait_options=wait_options,
|
|
229
229
|
method=method,
|
|
230
230
|
console=console,
|
|
231
|
+
client_type="cli",
|
|
231
232
|
)
|
|
232
233
|
except Exception as exc: # noqa: BLE001
|
|
233
234
|
fail(exc)
|
|
@@ -597,7 +598,16 @@ def raw_call(
|
|
|
597
598
|
runtime = runtime_from_ctx(ctx)
|
|
598
599
|
# Raw calls intentionally bypass fuzzy matching. Users can pass exact API payloads.
|
|
599
600
|
runtime.no_fuzzy = True
|
|
600
|
-
execute_tool(
|
|
601
|
+
execute_tool(
|
|
602
|
+
tool_name=tool,
|
|
603
|
+
action=None,
|
|
604
|
+
params={},
|
|
605
|
+
runtime=runtime,
|
|
606
|
+
raw_payload=payload,
|
|
607
|
+
method=method,
|
|
608
|
+
console=console,
|
|
609
|
+
client_type="cli",
|
|
610
|
+
)
|
|
601
611
|
except Exception as exc: # noqa: BLE001
|
|
602
612
|
fail(exc)
|
|
603
613
|
|
|
@@ -617,7 +627,7 @@ def task_call(ctx: typer.Context, task_id: str, action: str, tool: str | None) -
|
|
|
617
627
|
non_interactive=runtime.non_interactive,
|
|
618
628
|
)
|
|
619
629
|
payload = status_payload(task_id) if action == "status" else result_payload(task_id)
|
|
620
|
-
data = APIClient(debug=runtime.debug, console=err_console).request_tool(
|
|
630
|
+
data = APIClient(debug=runtime.debug, console=err_console, client_type="cli").request_tool(
|
|
621
631
|
endpoint=str(entry.get("endpoint")), payload=payload, api_key=api_key
|
|
622
632
|
).data
|
|
623
633
|
print_output(console, data, runtime.output_format, runtime.output)
|
|
@@ -945,6 +955,7 @@ def make_tool_app(adapter: ToolAdapter) -> typer.Typer:
|
|
|
945
955
|
runtime=runtime,
|
|
946
956
|
wait_options=wait_options,
|
|
947
957
|
console=console,
|
|
958
|
+
client_type="cli",
|
|
948
959
|
)
|
|
949
960
|
except Exception as exc: # noqa: BLE001
|
|
950
961
|
fail(exc)
|
|
@@ -977,6 +988,7 @@ def make_tool_app(adapter: ToolAdapter) -> typer.Typer:
|
|
|
977
988
|
raw_payload=payload,
|
|
978
989
|
method=method,
|
|
979
990
|
console=console,
|
|
991
|
+
client_type="cli",
|
|
980
992
|
)
|
|
981
993
|
except Exception as exc: # noqa: BLE001
|
|
982
994
|
fail(exc)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|