compshare-cli 0.3.4__tar.gz → 0.3.6__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.
Files changed (58) hide show
  1. compshare_cli-0.3.6/PKG-INFO +112 -0
  2. compshare_cli-0.3.6/README.md +87 -0
  3. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/__init__.py +1 -1
  4. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/cli.py +33 -1
  5. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/feedback.py +1 -1
  6. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/i18n.py +1 -3
  7. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/insights.py +63 -56
  8. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/location.py +2 -8
  9. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/sdk.py +10 -2
  10. compshare_cli-0.3.6/src/compshare_cli.egg-info/PKG-INFO +112 -0
  11. compshare_cli-0.3.6/tests/test_feedback.py +202 -0
  12. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_location.py +1 -3
  13. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_sdk.py +9 -0
  14. compshare_cli-0.3.4/PKG-INFO +0 -400
  15. compshare_cli-0.3.4/README.md +0 -375
  16. compshare_cli-0.3.4/src/compshare_cli.egg-info/PKG-INFO +0 -400
  17. compshare_cli-0.3.4/tests/test_feedback.py +0 -159
  18. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/LICENSE +0 -0
  19. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/pyproject.toml +0 -0
  20. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/setup.cfg +0 -0
  21. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/__main__.py +0 -0
  22. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/actions.py +0 -0
  23. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/api.py +0 -0
  24. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/__init__.py +0 -0
  25. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/ask.py +0 -0
  26. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/common.py +0 -0
  27. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/doctor.py +0 -0
  28. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/image.py +0 -0
  29. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/instance.py +0 -0
  30. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/storage.py +0 -0
  31. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/commands/team.py +0 -0
  32. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/config.py +0 -0
  33. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/errors.py +0 -0
  34. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/instance_templates.py +0 -0
  35. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/output.py +0 -0
  36. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/parsing.py +0 -0
  37. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/qa.py +0 -0
  38. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/remote_jobs.py +0 -0
  39. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/runtime.py +0 -0
  40. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/ssh.py +0 -0
  41. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli/ssh_cache.py +0 -0
  42. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/SOURCES.txt +0 -0
  43. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/dependency_links.txt +0 -0
  44. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/entry_points.txt +0 -0
  45. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/requires.txt +0 -0
  46. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/src/compshare_cli.egg-info/top_level.txt +0 -0
  47. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_actions.py +0 -0
  48. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_api.py +0 -0
  49. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_cli.py +0 -0
  50. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_config.py +0 -0
  51. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_instance_templates.py +0 -0
  52. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_output.py +0 -0
  53. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_parsing.py +0 -0
  54. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_qa.py +0 -0
  55. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_release_version.py +0 -0
  56. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_remote_jobs.py +0 -0
  57. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_ssh.py +0 -0
  58. {compshare_cli-0.3.4 → compshare_cli-0.3.6}/tests/test_ssh_cache.py +0 -0
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: compshare-cli
3
+ Version: 0.3.6
4
+ Summary: Command-line client for CompShare GPU compute
5
+ Author: CompShare
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/BennielAllan/compshare-cli
8
+ Project-URL: Repository, https://github.com/BennielAllan/compshare-cli
9
+ Project-URL: Changelog, https://github.com/BennielAllan/compshare-cli/blob/master/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/BennielAllan/compshare-cli/issues
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: click<9,>=8.1
15
+ Requires-Dist: pexpect<5,>=4.9; platform_system != "Windows"
16
+ Requires-Dist: rich<15,>=13
17
+ Requires-Dist: typer<1,>=0.12
18
+ Requires-Dist: ucloud-sdk-python3<0.12,>=0.11.103
19
+ Requires-Dist: urllib3<2,>=1.26.18; python_version < "3.10" and platform_system == "Darwin"
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest<10,>=8; extra == "dev"
22
+ Requires-Dist: pytest-cov<8,>=5; extra == "dev"
23
+ Requires-Dist: ruff<1,>=0.6; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # CompShare CLI
27
+
28
+ 在终端管理优云智算 GPU 实例、镜像、云盘、US3 挂载和团队资源。
29
+
30
+ - 交互式创建实例,实时查询规格、库存和价格
31
+ - 支持批量生命周期操作、等待状态和跨地域查询
32
+ - 支持可断线恢复的远程任务、状态查询和增量日志读取
33
+ - 支持社区/自定义镜像、云盘、团队额度与账单
34
+ - 默认中文帮助,可切换英文;所有命令支持 JSON 输出
35
+ - 可通过 `compshare ask` 查询产品使用和计费知识
36
+ - 可通过 `compshare feedback` 反馈 CLI 问题和建议
37
+
38
+ ## 安装
39
+
40
+ ```bash
41
+ pip install compshare-cli
42
+ pip install --upgrade compshare-cli
43
+ ```
44
+
45
+ ## 配置
46
+
47
+ ```bash
48
+ compshare config --name default
49
+ ```
50
+
51
+ 凭证保存在 `~/.config/compshare/config.json`,支持多个配置:
52
+
53
+ ```bash
54
+ compshare config list
55
+ compshare config use production
56
+ compshare --profile production instance list
57
+ ```
58
+
59
+ 也可以使用环境变量:
60
+
61
+ ```bash
62
+ export COMPSHARE_PUBLIC_KEY='...'
63
+ export COMPSHARE_PRIVATE_KEY='...'
64
+ ```
65
+
66
+ CLI 使用统计和反馈与业务 API 一样,通过当前 profile 的凭证签名后发送到
67
+ `https://api.compshare.cn/`;开发环境可使用 `COMPSHARE_INSIGHTS_URL` 覆盖网关地址。
68
+
69
+ ## 快速开始
70
+
71
+ ```bash
72
+ # 查询、创建和查看实例
73
+ compshare instance search --region cn-sh2 --zone cn-sh2-02
74
+ compshare instance create
75
+ compshare instance list --all
76
+
77
+ # 连接实例
78
+ compshare instance ssh INSTANCE_ID
79
+
80
+ # 查看帮助
81
+ compshare -h
82
+ compshare instance -h
83
+ ```
84
+
85
+ ## 命令概览
86
+
87
+ ```text
88
+ compshare config API 凭证配置
89
+ compshare feedback 反馈 CLI 问题或建议
90
+ compshare doctor 配置、鉴权、网络与 SSH 环境诊断
91
+ compshare ask 产品使用和计费问答
92
+ compshare instance GPU 实例、规格、库存、价格和生命周期
93
+ compshare image 平台、自定义、社区及共享镜像
94
+ compshare storage 云盘和 US3 挂载
95
+ compshare team 团队、邀请、成员额度、账单和审计
96
+ ```
97
+
98
+ ## Skill
99
+
100
+ 为 Codex、Claude Code、Cursor 等 AI Agent 安装 CompShare CLI Skill:
101
+
102
+ ```bash
103
+ npx skills add compshare-cn/compshare-cli --skill compshare-cli
104
+ ```
105
+
106
+ 完整说明见 [CompShare CLI Skill](skills/compshare-cli/SKILL.md)。
107
+
108
+ ## SDK
109
+
110
+ 如需通过 SDK 集成 CompShare API,可参考独立的
111
+ [CompShare Developer Examples](https://github.com/ucloud/compshare-developer-examples) 仓库。
112
+ 其中包含 Python、Go、Java、JavaScript 和 PHP 示例,覆盖 API 鉴权、GPU 实例创建、规格配置和状态查询。
@@ -0,0 +1,87 @@
1
+ # CompShare CLI
2
+
3
+ 在终端管理优云智算 GPU 实例、镜像、云盘、US3 挂载和团队资源。
4
+
5
+ - 交互式创建实例,实时查询规格、库存和价格
6
+ - 支持批量生命周期操作、等待状态和跨地域查询
7
+ - 支持可断线恢复的远程任务、状态查询和增量日志读取
8
+ - 支持社区/自定义镜像、云盘、团队额度与账单
9
+ - 默认中文帮助,可切换英文;所有命令支持 JSON 输出
10
+ - 可通过 `compshare ask` 查询产品使用和计费知识
11
+ - 可通过 `compshare feedback` 反馈 CLI 问题和建议
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ pip install compshare-cli
17
+ pip install --upgrade compshare-cli
18
+ ```
19
+
20
+ ## 配置
21
+
22
+ ```bash
23
+ compshare config --name default
24
+ ```
25
+
26
+ 凭证保存在 `~/.config/compshare/config.json`,支持多个配置:
27
+
28
+ ```bash
29
+ compshare config list
30
+ compshare config use production
31
+ compshare --profile production instance list
32
+ ```
33
+
34
+ 也可以使用环境变量:
35
+
36
+ ```bash
37
+ export COMPSHARE_PUBLIC_KEY='...'
38
+ export COMPSHARE_PRIVATE_KEY='...'
39
+ ```
40
+
41
+ CLI 使用统计和反馈与业务 API 一样,通过当前 profile 的凭证签名后发送到
42
+ `https://api.compshare.cn/`;开发环境可使用 `COMPSHARE_INSIGHTS_URL` 覆盖网关地址。
43
+
44
+ ## 快速开始
45
+
46
+ ```bash
47
+ # 查询、创建和查看实例
48
+ compshare instance search --region cn-sh2 --zone cn-sh2-02
49
+ compshare instance create
50
+ compshare instance list --all
51
+
52
+ # 连接实例
53
+ compshare instance ssh INSTANCE_ID
54
+
55
+ # 查看帮助
56
+ compshare -h
57
+ compshare instance -h
58
+ ```
59
+
60
+ ## 命令概览
61
+
62
+ ```text
63
+ compshare config API 凭证配置
64
+ compshare feedback 反馈 CLI 问题或建议
65
+ compshare doctor 配置、鉴权、网络与 SSH 环境诊断
66
+ compshare ask 产品使用和计费问答
67
+ compshare instance GPU 实例、规格、库存、价格和生命周期
68
+ compshare image 平台、自定义、社区及共享镜像
69
+ compshare storage 云盘和 US3 挂载
70
+ compshare team 团队、邀请、成员额度、账单和审计
71
+ ```
72
+
73
+ ## Skill
74
+
75
+ 为 Codex、Claude Code、Cursor 等 AI Agent 安装 CompShare CLI Skill:
76
+
77
+ ```bash
78
+ npx skills add compshare-cn/compshare-cli --skill compshare-cli
79
+ ```
80
+
81
+ 完整说明见 [CompShare CLI Skill](skills/compshare-cli/SKILL.md)。
82
+
83
+ ## SDK
84
+
85
+ 如需通过 SDK 集成 CompShare API,可参考独立的
86
+ [CompShare Developer Examples](https://github.com/ucloud/compshare-developer-examples) 仓库。
87
+ 其中包含 Python、Go、Java、JavaScript 和 PHP 示例,覆盖 API 鉴权、GPU 实例创建、规格配置和状态查询。
@@ -1,3 +1,3 @@
1
1
  """CompShare command-line client."""
2
2
 
3
- __version__ = "0.3.4"
3
+ __version__ = "0.3.6"
@@ -506,16 +506,45 @@ def _requested_language(argv: List[str]) -> Optional[str]:
506
506
  return requested
507
507
 
508
508
 
509
+ def _requested_profile(argv: List[str]) -> Optional[str]:
510
+ """Return the root --profile value, if present."""
511
+ index = 0
512
+ while index < len(argv):
513
+ option = argv[index]
514
+ if option == "--profile":
515
+ return argv[index + 1] if index + 1 < len(argv) else None
516
+ if option.startswith("--profile="):
517
+ return option.split("=", 1)[1] or None
518
+ if option in {"--lang"}:
519
+ index += 2
520
+ continue
521
+ if option.startswith("--lang=") or option in {
522
+ "--json",
523
+ "--show-sensitive",
524
+ "--version",
525
+ "-h",
526
+ "--help",
527
+ }:
528
+ index += 1
529
+ continue
530
+ if not option.startswith("-"):
531
+ break
532
+ index += 1
533
+ return None
534
+
535
+
509
536
  def main(args: Optional[List[str]] = None) -> None:
510
537
  original_argv = list(sys.argv[1:] if args is None else args)
511
538
  argv = list(original_argv)
512
539
  if not argv:
513
540
  argv = ["-h"]
514
541
  telemetry_command: Optional[str] = None
542
+ telemetry_profile: Optional[str] = None
515
543
  json_output = _global_flag_requested(argv, "--json")
516
544
  show_sensitive = _global_flag_requested(argv, "--show-sensitive")
517
545
  try:
518
546
  argv = _normalize_global_options(argv)
547
+ telemetry_profile = _requested_profile(argv)
519
548
  requested_language = _requested_language(argv)
520
549
  if requested_language is None:
521
550
  language = configured_language()
@@ -547,7 +576,10 @@ def main(args: Optional[List[str]] = None) -> None:
547
576
  raise SystemExit(1) from error
548
577
  finally:
549
578
  if telemetry_command:
550
- record_command(telemetry_command)
579
+ if telemetry_profile is None:
580
+ record_command(telemetry_command)
581
+ else:
582
+ record_command(telemetry_command, telemetry_profile)
551
583
  if isinstance(result, int) and result:
552
584
  raise SystemExit(result)
553
585
 
@@ -14,7 +14,7 @@ class FeedbackCategory(str, Enum):
14
14
 
15
15
 
16
16
  def run(state: Runtime, category: FeedbackCategory, message: str) -> None:
17
- response = submit_feedback(category.value, message)
17
+ response = submit_feedback(state.profile, category.value, message)
18
18
  Renderer(state.json_output, state.show_sensitive).success(
19
19
  tr("Thank you for your feedback."), response
20
20
  )
@@ -718,9 +718,7 @@ ZH_TRANSLATIONS: Dict[str, str] = {
718
718
  "Feedback service is not configured; set {variable}.": (
719
719
  "反馈服务尚未配置,请设置 {variable}。"
720
720
  ),
721
- "Insights service rejected the request with HTTP {status}.": (
722
- "数据服务拒绝了请求,HTTP 状态码为 {status}。"
723
- ),
721
+ "Insights service rejected the request: {detail}": "数据服务拒绝了请求:{detail}",
724
722
  "Unable to reach the insights service.": "无法连接数据服务。",
725
723
  "Insights service returned an invalid response.": "数据服务返回了无效响应。",
726
724
  "Thank you for your feedback.": "感谢反馈。",
@@ -7,16 +7,21 @@ import platform
7
7
  import subprocess
8
8
  import sys
9
9
  from datetime import datetime, timezone
10
- from typing import Any, Dict
11
- from urllib import error as urlerror
12
- from urllib import parse, request
10
+ from typing import Any, Dict, Optional
11
+ from urllib import parse
12
+
13
+ from ucloud.core import exc as ucloud_exc
13
14
 
14
15
  from compshare_cli import __version__
16
+ from compshare_cli.config import ConfigStore, Profile
15
17
  from compshare_cli.errors import CLIError
16
18
  from compshare_cli.i18n import tr
19
+ from compshare_cli.sdk import CompShareSDK
17
20
 
18
21
  ENDPOINT_ENV = "COMPSHARE_INSIGHTS_URL"
19
- DEFAULT_ENDPOINT = "http://117.50.180.139:27299"
22
+ DEFAULT_ENDPOINT = "https://api.compshare.cn"
23
+ EVENT_ACTION = "CreateCSCLIEvent"
24
+ FEEDBACK_ACTION = "CreateCSCLIFeedback"
20
25
 
21
26
 
22
27
  def now() -> str:
@@ -28,18 +33,21 @@ def os_name() -> str:
28
33
  return value or sys.platform.lower()
29
34
 
30
35
 
31
- def record_command(command: str) -> None:
36
+ def record_command(command: str, profile_name: Optional[str] = None) -> None:
32
37
  """Report a command in a detached process without delaying or affecting the CLI."""
33
38
  if not _base_url():
34
39
  return
35
- payload = {
36
- "command": command,
37
- "cli_version": __version__,
38
- "os": os_name(),
39
- "time": now(),
40
+ document = {
41
+ "profile_name": profile_name,
42
+ "payload": {
43
+ "Command": command,
44
+ "CLIVersion": __version__,
45
+ "OS": os_name(),
46
+ "OccurredAt": now(),
47
+ },
40
48
  }
41
49
  encoded = base64.urlsafe_b64encode(
42
- json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
50
+ json.dumps(document, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
43
51
  ).decode("ascii")
44
52
  kwargs: Dict[str, Any] = {
45
53
  "stdin": subprocess.DEVNULL,
@@ -60,7 +68,11 @@ def record_command(command: str) -> None:
60
68
  pass
61
69
 
62
70
 
63
- def submit_feedback(category: str, message: str) -> Dict[str, Any]:
71
+ def submit_feedback(
72
+ profile: Profile,
73
+ category: str,
74
+ message: str,
75
+ ) -> Dict[str, Any]:
64
76
  if category not in {"bug", "suggest"}:
65
77
  raise CLIError(tr("Feedback category must be bug or suggest."))
66
78
  normalized = message.strip()
@@ -75,17 +87,33 @@ def submit_feedback(category: str, message: str) -> Dict[str, Any]:
75
87
  variable=ENDPOINT_ENV,
76
88
  )
77
89
  )
78
- return _post(
79
- "/v1/feedback",
80
- {
81
- "category": category,
82
- "message": normalized,
83
- "cli_version": __version__,
84
- "os": os_name(),
85
- "time": now(),
86
- },
87
- timeout=5.0,
88
- )
90
+ try:
91
+ response = _invoke(
92
+ profile,
93
+ FEEDBACK_ACTION,
94
+ {
95
+ "Category": category,
96
+ "Content": normalized,
97
+ "CLIVersion": __version__,
98
+ "OS": os_name(),
99
+ "OccurredAt": now(),
100
+ },
101
+ )
102
+ feedback_id = response.get("Id") if isinstance(response, dict) else None
103
+ if not feedback_id:
104
+ raise ValueError("missing feedback ID")
105
+ return {"ok": True, "id": feedback_id}
106
+ except ucloud_exc.RetCodeException as error:
107
+ raise CLIError(
108
+ tr(
109
+ "Insights service rejected the request: {detail}",
110
+ detail=error.message or str(error.code),
111
+ )
112
+ ) from error
113
+ except (ucloud_exc.UCloudException, TimeoutError, OSError) as error:
114
+ raise CLIError(tr("Unable to reach the insights service.")) from error
115
+ except Exception as error:
116
+ raise CLIError(tr("Insights service returned an invalid response.")) from error
89
117
 
90
118
 
91
119
  def _base_url() -> str:
@@ -96,43 +124,22 @@ def _base_url() -> str:
96
124
  return value if parsed.scheme in {"http", "https"} and parsed.netloc else ""
97
125
 
98
126
 
99
- def _post(path: str, payload: Dict[str, Any], *, timeout: float) -> Dict[str, Any]:
100
- body = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
101
- req = request.Request(
102
- f"{_base_url()}{path}",
103
- data=body,
104
- headers={
105
- "Accept": "application/json",
106
- "Content-Type": "application/json",
107
- "User-Agent": f"compshare-cli/{__version__}",
108
- },
109
- method="POST",
110
- )
111
- try:
112
- with request.urlopen(req, timeout=timeout) as response:
113
- content = response.read()
114
- except urlerror.HTTPError as error:
115
- raise CLIError(
116
- tr("Insights service rejected the request with HTTP {status}.", status=error.code)
117
- ) from error
118
- except (urlerror.URLError, TimeoutError, OSError) as error:
119
- raise CLIError(tr("Unable to reach the insights service.")) from error
120
- if not content:
121
- return {"ok": True}
122
- try:
123
- result = json.loads(content.decode("utf-8"))
124
- except (UnicodeDecodeError, json.JSONDecodeError) as error:
125
- raise CLIError(tr("Insights service returned an invalid response.")) from error
126
- if not isinstance(result, dict):
127
- raise CLIError(tr("Insights service returned an invalid response."))
128
- return result
127
+ def _invoke(profile: Profile, action: str, payload: Dict[str, Any]) -> Dict[str, Any]:
128
+ return CompShareSDK(profile, base_url=_base_url()).invoke(action, payload)
129
129
 
130
130
 
131
131
  def _send_event(encoded: str) -> None:
132
132
  try:
133
- payload = json.loads(base64.urlsafe_b64decode(encoded.encode("ascii")).decode("utf-8"))
134
- if isinstance(payload, dict) and _base_url():
135
- _post("/v1/events", payload, timeout=3.0)
133
+ document = json.loads(base64.urlsafe_b64decode(encoded.encode("ascii")).decode("utf-8"))
134
+ if not isinstance(document, dict) or not _base_url():
135
+ return
136
+ payload = document.get("payload")
137
+ if not isinstance(payload, dict):
138
+ return
139
+ raw_profile_name = document.get("profile_name")
140
+ profile_name = str(raw_profile_name) if raw_profile_name else None
141
+ profile = ConfigStore().load_profile(profile_name)
142
+ _invoke(profile, EVENT_ACTION, payload)
136
143
  except Exception:
137
144
  pass
138
145
 
@@ -77,11 +77,7 @@ def locate_disk(
77
77
  zone = str(disk.get("Zone") or "")
78
78
  locations = supported_locations(state, request_region=request_region)
79
79
  location = next(
80
- (
81
- item
82
- for item in locations
83
- if str(item.get("Zone") or "") == zone and item.get("Region")
84
- ),
80
+ (item for item in locations if str(item.get("Zone") or "") == zone and item.get("Region")),
85
81
  None,
86
82
  )
87
83
  if location is None:
@@ -95,8 +91,6 @@ def locate_disk(
95
91
  region = str(location["Region"])
96
92
  mount_instance = disk.get("MountInstance")
97
93
  host = (
98
- {"UHostId": str(mount_instance), "Region": region, "Zone": zone}
99
- if mount_instance
100
- else None
94
+ {"UHostId": str(mount_instance), "Region": region, "Zone": zone} if mount_instance else None
101
95
  )
102
96
  return region, zone, host, disk
@@ -17,13 +17,21 @@ class CompShareSDK:
17
17
  lag behind the public API and silently discard newer fields.
18
18
  """
19
19
 
20
- def __init__(self, profile: Profile, region: Optional[str] = None) -> None:
20
+ def __init__(
21
+ self,
22
+ profile: Profile,
23
+ region: Optional[str] = None,
24
+ base_url: Optional[str] = None,
25
+ ) -> None:
21
26
  logger = logging.getLogger("compshare_cli.ucloud")
22
27
  logger.handlers.clear()
23
28
  logger.addHandler(logging.NullHandler())
24
29
  logger.setLevel(logging.CRITICAL)
25
30
  logger.propagate = False
26
- self._service = Client(profile.sdk_config(region), logger=logger).ucompshare()
31
+ config = profile.sdk_config(region)
32
+ if base_url is not None:
33
+ config["base_url"] = base_url
34
+ self._service = Client(config, logger=logger).ucompshare()
27
35
 
28
36
  def invoke(self, action: str, params: Dict[str, Any]) -> Dict[str, Any]:
29
37
  return self._service.invoke(action, params)
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: compshare-cli
3
+ Version: 0.3.6
4
+ Summary: Command-line client for CompShare GPU compute
5
+ Author: CompShare
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/BennielAllan/compshare-cli
8
+ Project-URL: Repository, https://github.com/BennielAllan/compshare-cli
9
+ Project-URL: Changelog, https://github.com/BennielAllan/compshare-cli/blob/master/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/BennielAllan/compshare-cli/issues
11
+ Requires-Python: >=3.9
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: click<9,>=8.1
15
+ Requires-Dist: pexpect<5,>=4.9; platform_system != "Windows"
16
+ Requires-Dist: rich<15,>=13
17
+ Requires-Dist: typer<1,>=0.12
18
+ Requires-Dist: ucloud-sdk-python3<0.12,>=0.11.103
19
+ Requires-Dist: urllib3<2,>=1.26.18; python_version < "3.10" and platform_system == "Darwin"
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest<10,>=8; extra == "dev"
22
+ Requires-Dist: pytest-cov<8,>=5; extra == "dev"
23
+ Requires-Dist: ruff<1,>=0.6; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # CompShare CLI
27
+
28
+ 在终端管理优云智算 GPU 实例、镜像、云盘、US3 挂载和团队资源。
29
+
30
+ - 交互式创建实例,实时查询规格、库存和价格
31
+ - 支持批量生命周期操作、等待状态和跨地域查询
32
+ - 支持可断线恢复的远程任务、状态查询和增量日志读取
33
+ - 支持社区/自定义镜像、云盘、团队额度与账单
34
+ - 默认中文帮助,可切换英文;所有命令支持 JSON 输出
35
+ - 可通过 `compshare ask` 查询产品使用和计费知识
36
+ - 可通过 `compshare feedback` 反馈 CLI 问题和建议
37
+
38
+ ## 安装
39
+
40
+ ```bash
41
+ pip install compshare-cli
42
+ pip install --upgrade compshare-cli
43
+ ```
44
+
45
+ ## 配置
46
+
47
+ ```bash
48
+ compshare config --name default
49
+ ```
50
+
51
+ 凭证保存在 `~/.config/compshare/config.json`,支持多个配置:
52
+
53
+ ```bash
54
+ compshare config list
55
+ compshare config use production
56
+ compshare --profile production instance list
57
+ ```
58
+
59
+ 也可以使用环境变量:
60
+
61
+ ```bash
62
+ export COMPSHARE_PUBLIC_KEY='...'
63
+ export COMPSHARE_PRIVATE_KEY='...'
64
+ ```
65
+
66
+ CLI 使用统计和反馈与业务 API 一样,通过当前 profile 的凭证签名后发送到
67
+ `https://api.compshare.cn/`;开发环境可使用 `COMPSHARE_INSIGHTS_URL` 覆盖网关地址。
68
+
69
+ ## 快速开始
70
+
71
+ ```bash
72
+ # 查询、创建和查看实例
73
+ compshare instance search --region cn-sh2 --zone cn-sh2-02
74
+ compshare instance create
75
+ compshare instance list --all
76
+
77
+ # 连接实例
78
+ compshare instance ssh INSTANCE_ID
79
+
80
+ # 查看帮助
81
+ compshare -h
82
+ compshare instance -h
83
+ ```
84
+
85
+ ## 命令概览
86
+
87
+ ```text
88
+ compshare config API 凭证配置
89
+ compshare feedback 反馈 CLI 问题或建议
90
+ compshare doctor 配置、鉴权、网络与 SSH 环境诊断
91
+ compshare ask 产品使用和计费问答
92
+ compshare instance GPU 实例、规格、库存、价格和生命周期
93
+ compshare image 平台、自定义、社区及共享镜像
94
+ compshare storage 云盘和 US3 挂载
95
+ compshare team 团队、邀请、成员额度、账单和审计
96
+ ```
97
+
98
+ ## Skill
99
+
100
+ 为 Codex、Claude Code、Cursor 等 AI Agent 安装 CompShare CLI Skill:
101
+
102
+ ```bash
103
+ npx skills add compshare-cn/compshare-cli --skill compshare-cli
104
+ ```
105
+
106
+ 完整说明见 [CompShare CLI Skill](skills/compshare-cli/SKILL.md)。
107
+
108
+ ## SDK
109
+
110
+ 如需通过 SDK 集成 CompShare API,可参考独立的
111
+ [CompShare Developer Examples](https://github.com/ucloud/compshare-developer-examples) 仓库。
112
+ 其中包含 Python、Go、Java、JavaScript 和 PHP 示例,覆盖 API 鉴权、GPU 实例创建、规格配置和状态查询。