cheso-cli 0.2.0__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.
- cheso_cli/__init__.py +12 -0
- cheso_cli/__main__.py +5 -0
- cheso_cli/auth.py +128 -0
- cheso_cli/cli.py +864 -0
- cheso_cli/client.py +534 -0
- cheso_cli/config.py +108 -0
- cheso_cli/credentials.py +235 -0
- cheso_cli/errors.py +56 -0
- cheso_cli/legacy_commands.py +93 -0
- cheso_cli/oauth.py +797 -0
- cheso_cli/skill/SKILL.md +83 -0
- cheso_cli/skill_install.py +119 -0
- cheso_cli/tasks.py +834 -0
- cheso_cli/transfer.py +294 -0
- cheso_cli-0.2.0.dist-info/METADATA +164 -0
- cheso_cli-0.2.0.dist-info/RECORD +18 -0
- cheso_cli-0.2.0.dist-info/WHEEL +4 -0
- cheso_cli-0.2.0.dist-info/entry_points.txt +4 -0
cheso_cli/skill/SKILL.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cheso
|
|
3
|
+
description: Create finished deliverables with Cheso (cheso.ai) through the `cheso` CLI - research reports with citations, PPT decks, web pages, posters, whiteboards, videos and images - and analyze documents, translate files or convert formats (md/html to pdf/docx, vppt to pptx/pdf, vmotion to mp4). Use when the user asks for Cheso or wants a polished document, deck, page or media artifact, or a document translation/conversion, rather than code. Tasks take minutes and spend the user's Cheso credits.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cheso
|
|
7
|
+
|
|
8
|
+
Cheso is an AI agent service that turns a prompt (plus optional files) into finished work: cited research
|
|
9
|
+
reports, PPT decks, web pages, posters, whiteboards, videos, images, document analysis, translation and format
|
|
10
|
+
conversion. Results are files you download into the working directory; the work also stays in the user's Cheso
|
|
11
|
+
project on the website, where they can view and edit it.
|
|
12
|
+
|
|
13
|
+
Prefer Cheso when the user wants a polished artifact (deck, report, page, poster, video) or mentions Cheso.
|
|
14
|
+
Do not use it for code changes, quick factual answers, or anything you can do directly in a few seconds.
|
|
15
|
+
|
|
16
|
+
## Before the first task
|
|
17
|
+
|
|
18
|
+
- `cheso whoami --json` checks the login. If it exits 4, sign in with a code the user approves in their browser:
|
|
19
|
+
1. Run `cheso login --device --no-wait --json`. Show the user `verification_uri` and `user_code` and ask them to
|
|
20
|
+
open the page (on any device), sign in to Cheso and enter the code.
|
|
21
|
+
2. Right away run `cheso login --wait --timeout 540 --json` (in Claude Code pass a 600000 ms Bash timeout). It
|
|
22
|
+
returns when they approve. Exit 6: still waiting, run it again. `error.kind` `login_denied`: they refused, stop.
|
|
23
|
+
`login_expired`: start again from step 1.
|
|
24
|
+
Never open the page or enter the code yourself; only the user approves. Alternatively the user can run
|
|
25
|
+
`cheso login` in their own terminal (it opens a browser). Add `--site cn` to every command for zhishi.qq.com.
|
|
26
|
+
- Uploads go to the user's Cheso account and every task spends their credits. Only upload files the user asked
|
|
27
|
+
you to use; never upload secrets or credentials.
|
|
28
|
+
|
|
29
|
+
## Run a task
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cheso task create --prompt "Make a 10-slide PPT deck for investors about ./notes.pdf, in English, clean style" \
|
|
33
|
+
--file ./notes.pdf --wait --timeout 540 --output-dir ./cheso-output --json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Write a complete prompt: topic, goal, audience, length/pages, language, style and output format.
|
|
37
|
+
- `--file PATH` (repeatable) uploads local files; `--file-id ID` reuses an uploaded or project file.
|
|
38
|
+
- `--project ID` continues or revises earlier work in the same project (use `project_id` from a previous result).
|
|
39
|
+
- `--agent-type image_edit` edits or generates images from attached image files; the default is `cheso`.
|
|
40
|
+
- Tasks usually take several minutes. `--timeout` counts from the start of the command and also covers downloading
|
|
41
|
+
the results: no request starts after it, so the call returns within about `--timeout` seconds (uploading `--file`
|
|
42
|
+
inputs and starting the task are never cut short). Keep it well below your shell tool's own limit (in Claude Code
|
|
43
|
+
pass a 600000 ms Bash timeout and use `--timeout 540`).
|
|
44
|
+
- If it is still running (exit 6), run `cheso task wait <task_id> --timeout 540 --output-dir ./cheso-output --json`
|
|
45
|
+
again with the same id. Never start a second task for the same request.
|
|
46
|
+
- When it finishes, the result files are saved into `--output-dir` (default: current directory; existing files are
|
|
47
|
+
never overwritten, a ` (n)` suffix is added). Tell the user the saved paths, `answer` and `project_url`.
|
|
48
|
+
- If you passed `--site` or `--base-url`, pass it again on every follow-up command for that task. The `next` field
|
|
49
|
+
already includes it and can be run as given.
|
|
50
|
+
|
|
51
|
+
## Exit codes
|
|
52
|
+
|
|
53
|
+
| Code | Meaning | What to do |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| 0 | Done | Use `files[].saved_to`, `answer`, `project_url` (with `--no-download`, nothing is saved: `cheso file download <file_id> --version <version>`) |
|
|
56
|
+
| 1 | Error, or the task failed | Read `error.message` (or `failure_reason`); tell the user; do not loop on retries. A failed task may still list partial `files`; those with `error` were not downloaded |
|
|
57
|
+
| 2 | Bad command | Fix the flags (`cheso <command> --help`) |
|
|
58
|
+
| 3 | Cheso asked a question | Show `question.questions` to the user (or decide if they delegated it), then `cheso task reply <task_id> --answer "<exact question>=<answer>"` (or `--answer "1=<answer>"`, several `--answer` for several questions, labels joined with ", " for multi-select, or `--skip`), then `cheso task wait <task_id>` |
|
|
59
|
+
| 4 | Login required | Sign in with `cheso login --device --no-wait --json` as described above, then retry |
|
|
60
|
+
| 5 | Not enough credits | Give the user `topup_url`; retry only after they top up |
|
|
61
|
+
| 6 | Still running after `--timeout` | Run `cheso task wait <task_id>` again |
|
|
62
|
+
| 7 | Rate limited or project busy | Retry the same command later: if `running_task_id` is given, first `cheso task wait <running_task_id>`; otherwise wait `retry_after` seconds if given, else a few seconds (`project_busy`) or a minute |
|
|
63
|
+
| 8 | The task succeeded, but some result files were not downloaded | Files with `saved_to` are fine; run the `next` command (`cheso file download ...`) for the rest. Never start the task again |
|
|
64
|
+
|
|
65
|
+
## Other commands
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cheso task get <task_id> --json # status, answer, files, question (no download)
|
|
69
|
+
cheso task wait <task_id> --json # wait; downloads results (--no-download to skip)
|
|
70
|
+
cheso task cancel <task_id>
|
|
71
|
+
cheso file upload ./data.xlsx [--project ID] --json # prints file_id
|
|
72
|
+
cheso file list --project <project_id> --json
|
|
73
|
+
cheso file download <file_id> --output-dir ./cheso-output
|
|
74
|
+
cheso convert <file_id> --to pdf --wait --json # unsupported targets are listed on error
|
|
75
|
+
cheso translate <file_id> --to en [--from zh] --wait --json
|
|
76
|
+
cheso credits --json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`task wait` / `task get` also accept conversion (`cvt_...`) and translation (`tlj_...`) ids.
|
|
80
|
+
|
|
81
|
+
With `--json`, stdout is one JSON document (errors: `{"error": {"kind", "message", "exit_code", ...}}`) and
|
|
82
|
+
progress goes to stderr. Useful fields: `task_id`, `status`, `done`, `needs_input`, `question`, `answer`,
|
|
83
|
+
`files[]` (`file_id`, `name`, `saved_to`), `project_id`, `project_url`, `failure_reason`, `topup_url`, `next`.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""为 Claude Code 和 Codex 安装包内附带的 Agent 技能(SKILL.md)。
|
|
2
|
+
|
|
3
|
+
安装位置:
|
|
4
|
+
- Claude Code:用户级 ``~/.claude/skills/cheso/``,项目级 ``./.claude/skills/cheso/``。
|
|
5
|
+
- Codex:用户级 ``~/.agents/skills/cheso/``,仓库级 ``./.agents/skills/cheso/``。
|
|
6
|
+
Codex 从 ``$HOME/.agents/skills`` 及仓库根目录到当前工作目录之间各层的 ``.agents/skills`` 读取技能;
|
|
7
|
+
``$CODEX_HOME/skills`` 仅用于向后兼容,见 openai/codex 的 ``codex-rs/ext/skills/src/host_roots.rs``。
|
|
8
|
+
|
|
9
|
+
安装文件旁的小标记记录写入内容的哈希。未被修改的旧副本会原地升级;用户修改过的副本仅在传入
|
|
10
|
+
``--force`` 时才会被替换。
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import contextlib
|
|
16
|
+
import hashlib
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import tempfile
|
|
20
|
+
from importlib import resources
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from cheso_cli.config import VERSION
|
|
25
|
+
from cheso_cli.errors import CliError
|
|
26
|
+
|
|
27
|
+
SKILL_NAME = "cheso"
|
|
28
|
+
SKILL_FILE = "SKILL.md"
|
|
29
|
+
MARKER_FILE = ".cheso-cli-install.json"
|
|
30
|
+
TARGETS = ("claude", "codex")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def skill_text() -> str:
|
|
34
|
+
return resources.files("cheso_cli").joinpath("skill").joinpath(SKILL_FILE).read_text(encoding="utf-8")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def skill_dirs(target: str, *, project: bool, home: Path, cwd: Path) -> list[tuple[str, Path]]:
|
|
38
|
+
names = TARGETS if target == "all" else (target,)
|
|
39
|
+
base = cwd if project else home
|
|
40
|
+
roots = {"claude": base / ".claude" / "skills", "codex": base / ".agents" / "skills"}
|
|
41
|
+
return [(name, roots[name] / SKILL_NAME) for name in names]
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _sha256(text: str) -> str:
|
|
45
|
+
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _read_marker(directory: Path) -> dict[str, Any]:
|
|
49
|
+
try:
|
|
50
|
+
data = json.loads((directory / MARKER_FILE).read_text(encoding="utf-8"))
|
|
51
|
+
except (OSError, ValueError):
|
|
52
|
+
return {}
|
|
53
|
+
return data if isinstance(data, dict) else {}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _write_atomic(path: Path, text: str) -> None:
|
|
57
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
58
|
+
fd, tmp = tempfile.mkstemp(prefix=".cheso-", suffix=".tmp", dir=path.parent)
|
|
59
|
+
try:
|
|
60
|
+
with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as f:
|
|
61
|
+
f.write(text)
|
|
62
|
+
mask = os.umask(0)
|
|
63
|
+
os.umask(mask)
|
|
64
|
+
os.chmod(tmp, 0o666 & ~mask)
|
|
65
|
+
os.replace(tmp, path)
|
|
66
|
+
except BaseException:
|
|
67
|
+
with contextlib.suppress(OSError):
|
|
68
|
+
os.unlink(tmp)
|
|
69
|
+
raise
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def install(
|
|
73
|
+
target: str = "all",
|
|
74
|
+
*,
|
|
75
|
+
project: bool = False,
|
|
76
|
+
force: bool = False,
|
|
77
|
+
home: Path | None = None,
|
|
78
|
+
cwd: Path | None = None,
|
|
79
|
+
) -> list[dict[str, Any]]:
|
|
80
|
+
"""安装到所有选定位置;尝试完全部位置后,只要任一位置拒绝安装就抛出 CliError。"""
|
|
81
|
+
if target not in (*TARGETS, "all"):
|
|
82
|
+
raise CliError(f"unknown target {target!r}", kind="usage")
|
|
83
|
+
content = skill_text()
|
|
84
|
+
digest = _sha256(content)
|
|
85
|
+
results: list[dict[str, Any]] = []
|
|
86
|
+
for name, directory in skill_dirs(target, project=project, home=home or Path.home(), cwd=cwd or Path.cwd()):
|
|
87
|
+
path = directory / SKILL_FILE
|
|
88
|
+
try:
|
|
89
|
+
existing = path.read_text(encoding="utf-8") if path.exists() else None
|
|
90
|
+
except OSError as e:
|
|
91
|
+
raise CliError(f"cannot read {path}: {e.strerror or e}") from e
|
|
92
|
+
if existing == content:
|
|
93
|
+
action = "unchanged"
|
|
94
|
+
elif existing is None:
|
|
95
|
+
action = "installed"
|
|
96
|
+
elif _read_marker(directory).get("sha256") == _sha256(existing):
|
|
97
|
+
action = "updated"
|
|
98
|
+
elif force:
|
|
99
|
+
action = "replaced"
|
|
100
|
+
else:
|
|
101
|
+
results.append({"target": name, "path": str(path), "action": "refused"})
|
|
102
|
+
continue
|
|
103
|
+
try:
|
|
104
|
+
if action != "unchanged":
|
|
105
|
+
_write_atomic(path, content)
|
|
106
|
+
_write_atomic(directory / MARKER_FILE, json.dumps({"sha256": digest, "version": VERSION}) + "\n")
|
|
107
|
+
except OSError as e:
|
|
108
|
+
raise CliError(f"cannot write {path}: {e.strerror or e}") from e
|
|
109
|
+
results.append({"target": name, "path": str(path), "action": action})
|
|
110
|
+
refused = [r["path"] for r in results if r["action"] == "refused"]
|
|
111
|
+
if refused:
|
|
112
|
+
raise CliError(
|
|
113
|
+
"Not overwriting a SKILL.md that was modified or not installed by cheso: "
|
|
114
|
+
+ ", ".join(refused)
|
|
115
|
+
+ ". Re-run with --force to replace it.",
|
|
116
|
+
kind="skill_modified",
|
|
117
|
+
extra={"results": results},
|
|
118
|
+
)
|
|
119
|
+
return results
|