chatup 0.2.3__tar.gz → 0.2.5__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.
- {chatup-0.2.3/src/chatup.egg-info → chatup-0.2.5}/PKG-INFO +6 -5
- {chatup-0.2.3 → chatup-0.2.5}/README.md +5 -4
- {chatup-0.2.3 → chatup-0.2.5}/pyproject.toml +3 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/__init__.py +1 -1
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/cli.py +2 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/commands/chrome_for_testing.py +1 -1
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/commands/chromedriver.py +1 -1
- chatup-0.2.5/src/chatup/commands/playwright.py +213 -0
- chatup-0.2.5/src/chatup/config.py +45 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/interaction/command_schema.py +21 -5
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/interaction/policy.py +17 -3
- chatup-0.2.5/src/chatup/playwright.py +62 -0
- chatup-0.2.5/src/chatup/runtime/__init__.py +6 -0
- chatup-0.2.5/src/chatup/runtime/playwright.py +444 -0
- chatup-0.2.5/src/chatup/setup/cursor_agent.py +459 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/elements.py +132 -0
- {chatup-0.2.3 → chatup-0.2.5/src/chatup.egg-info}/PKG-INFO +6 -5
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup.egg-info/SOURCES.txt +8 -0
- chatup-0.2.5/src/chatup.egg-info/entry_points.txt +5 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_browser_backend_cli.py +6 -1
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_cli_tree_docs.py +2 -0
- chatup-0.2.5/tests/test_cursor_agent_setup.py +290 -0
- chatup-0.2.5/tests/test_playwright.py +160 -0
- chatup-0.2.5/tests/test_playwright_cli.py +104 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_pyproject_metadata.py +19 -6
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_version.py +2 -2
- chatup-0.2.3/src/chatup/runtime/__init__.py +0 -5
- chatup-0.2.3/src/chatup.egg-info/entry_points.txt +0 -2
- {chatup-0.2.3 → chatup-0.2.5}/LICENSE +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/setup.cfg +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/chrome_for_testing.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/chromedriver.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/commands/__init__.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/const.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/interaction/__init__.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/interaction/warnings.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/runtime/_managed_artifact.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/runtime/chrome_for_testing.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/runtime/chromedriver.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/__init__.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/assets/hermes/install.sh +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/assets/nvm.sh +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/cc_connect.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/claude.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/cli.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/codex.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/crs.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/docker.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/frp.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/gitea.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/hermes.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/lark_cli.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/mode_prompt.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/mysql.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/nginx.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/nodejs.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/opencode.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/shell_rc.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/uv.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/__init__.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/cli.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/core.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/options.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/render.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/templates/default/en/AGENTS.md +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/templates/default/en/discussion/README.md +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/templates/default/en/projects/README.md +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/templates/default/zh/AGENTS.md +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/templates/default/zh/discussion/README.md +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace/templates/default/zh/projects/README.md +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/workspace.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/setup/zsh.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/utils/__init__.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/utils/custom_logger.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup/utils/pathing.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup.egg-info/dependency_links.txt +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup.egg-info/requires.txt +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/src/chatup.egg-info/top_level.txt +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_chrome_for_testing.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_chromedriver.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_crs_setup.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_publish_workflow.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_setup_cli.py +0 -0
- {chatup-0.2.3 → chatup-0.2.5}/tests/test_workspace_setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatup
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.5
|
|
4
4
|
Summary: ChatArch setup CLI extracted from ChatTool
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -37,7 +37,7 @@ ChatUp 是 ChatArch 的独立环境与工具安装 CLI。它承接原来 `chatto
|
|
|
37
37
|
| 场景 | 文档 |
|
|
38
38
|
| --- | --- |
|
|
39
39
|
| 从空机器验证 ChatUp、Python runtime 和 workspace | `docs/quickstart.md` |
|
|
40
|
-
|
|
|
40
|
+
| 阅读完整顶层 CLI 树和独立 CFT/ChromeDriver/Playwright contract | `docs/cli-tree.md` |
|
|
41
41
|
| 查看命令分组、参数边界和服务默认路径 | `docs/commands.md` |
|
|
42
42
|
| 校对哪些 ChatArch setup 流程已经有一等命令 | `docs/capability-map.md` |
|
|
43
43
|
| 理解 `chatup workspace` 创建的目录和项目记录约定 | `docs/workspace.md` |
|
|
@@ -50,6 +50,7 @@ chatup --help
|
|
|
50
50
|
chatup doctor
|
|
51
51
|
chatup uv
|
|
52
52
|
chatup chrome-for-testing install --channel stable -I
|
|
53
|
+
chatup playwright install 1.61.1 -I
|
|
53
54
|
chatup workspace default ~/Playground
|
|
54
55
|
```
|
|
55
56
|
|
|
@@ -67,12 +68,12 @@ chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
|
|
|
67
68
|
|
|
68
69
|
| 能力组 | 命令 |
|
|
69
70
|
| --- | --- |
|
|
70
|
-
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`frp` |
|
|
71
|
+
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`playwright`、`frp` |
|
|
71
72
|
| 工作区脚手架 | `workspace` |
|
|
72
73
|
| 本地服务安装 | `gitea`、`mysql`、`nginx`、`crs` |
|
|
73
|
-
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`opencode`、`hermes`、`lark-cli` |
|
|
74
|
+
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
|
|
74
75
|
|
|
75
|
-
所有新增安装项默认目录都收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/chattea`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local
|
|
76
|
+
所有新增安装项默认目录都收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/playwright`、`~/.chatarch/chattea`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local`。`cursor-agent` 额外注册 ChatEnv `CursorAgent` profile,并支持 `-e/--env` 从 env 文件或 profile 快速配置迁移来的 Cursor token。更完整的能力边界见 `docs/capability-map.md`。
|
|
76
77
|
|
|
77
78
|
## 开发
|
|
78
79
|
|
|
@@ -11,7 +11,7 @@ ChatUp 是 ChatArch 的独立环境与工具安装 CLI。它承接原来 `chatto
|
|
|
11
11
|
| 场景 | 文档 |
|
|
12
12
|
| --- | --- |
|
|
13
13
|
| 从空机器验证 ChatUp、Python runtime 和 workspace | `docs/quickstart.md` |
|
|
14
|
-
|
|
|
14
|
+
| 阅读完整顶层 CLI 树和独立 CFT/ChromeDriver/Playwright contract | `docs/cli-tree.md` |
|
|
15
15
|
| 查看命令分组、参数边界和服务默认路径 | `docs/commands.md` |
|
|
16
16
|
| 校对哪些 ChatArch setup 流程已经有一等命令 | `docs/capability-map.md` |
|
|
17
17
|
| 理解 `chatup workspace` 创建的目录和项目记录约定 | `docs/workspace.md` |
|
|
@@ -24,6 +24,7 @@ chatup --help
|
|
|
24
24
|
chatup doctor
|
|
25
25
|
chatup uv
|
|
26
26
|
chatup chrome-for-testing install --channel stable -I
|
|
27
|
+
chatup playwright install 1.61.1 -I
|
|
27
28
|
chatup workspace default ~/Playground
|
|
28
29
|
```
|
|
29
30
|
|
|
@@ -41,12 +42,12 @@ chatup crs --install-dir ~/.chatarch/crs/local --port 12392 --redis-port 6379
|
|
|
41
42
|
|
|
42
43
|
| 能力组 | 命令 |
|
|
43
44
|
| --- | --- |
|
|
44
|
-
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`frp` |
|
|
45
|
+
| 基础运行环境 | `doctor`、`uv`、`nodejs`、`docker`、`zsh`、`chrome-for-testing`、`chromedriver`、`playwright`、`frp` |
|
|
45
46
|
| 工作区脚手架 | `workspace` |
|
|
46
47
|
| 本地服务安装 | `gitea`、`mysql`、`nginx`、`crs` |
|
|
47
|
-
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`opencode`、`hermes`、`lark-cli` |
|
|
48
|
+
| Agent 工具链 | `cc-connect`、`claude`、`codex`、`cursor-agent`、`opencode`、`hermes`、`lark-cli` |
|
|
48
49
|
|
|
49
|
-
所有新增安装项默认目录都收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/chattea`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local
|
|
50
|
+
所有新增安装项默认目录都收敛到 `~/.chatarch/...`,例如 `~/.chatarch/chrome-for-testing`、`~/.chatarch/chromedriver`、`~/.chatarch/playwright`、`~/.chatarch/chattea`、`~/.chatarch/chatdata`、`~/.chatarch/nginx` 和 `~/.chatarch/crs/local`。`cursor-agent` 额外注册 ChatEnv `CursorAgent` profile,并支持 `-e/--env` 从 env 文件或 profile 快速配置迁移来的 Cursor token。更完整的能力边界见 `docs/capability-map.md`。
|
|
50
51
|
|
|
51
52
|
## 开发
|
|
52
53
|
|
|
@@ -5,6 +5,7 @@ import click
|
|
|
5
5
|
from chatup import __version__
|
|
6
6
|
from chatup.commands.chrome_for_testing import cli as chrome_for_testing_cli
|
|
7
7
|
from chatup.commands.chromedriver import cli as chromedriver_cli
|
|
8
|
+
from chatup.commands.playwright import cli as playwright_cli
|
|
8
9
|
from chatup.setup.cli import register_setup_commands
|
|
9
10
|
|
|
10
11
|
|
|
@@ -23,6 +24,7 @@ def doctor() -> None:
|
|
|
23
24
|
register_setup_commands(main)
|
|
24
25
|
main.add_command(chrome_for_testing_cli)
|
|
25
26
|
main.add_command(chromedriver_cli)
|
|
27
|
+
main.add_command(playwright_cli)
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
from chatup.interaction import (
|
|
10
|
+
CommandField,
|
|
11
|
+
CommandSchema,
|
|
12
|
+
add_interactive_option,
|
|
13
|
+
resolve_command_inputs,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
import chatup.playwright as backend
|
|
17
|
+
|
|
18
|
+
OUTPUT_TYPES = ("text", "json")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _validate_version(value: Any, _values: dict[str, Any]) -> str | None:
|
|
22
|
+
if re.fullmatch(r"\d+\.\d+\.\d+", str(value).strip()):
|
|
23
|
+
return None
|
|
24
|
+
return "Playwright version must contain three numeric components"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
VERSION_SCHEMA = CommandSchema(
|
|
28
|
+
name="playwright version",
|
|
29
|
+
fields=(
|
|
30
|
+
CommandField(
|
|
31
|
+
"version",
|
|
32
|
+
prompt="Exact Playwright version",
|
|
33
|
+
required=True,
|
|
34
|
+
normalizer=lambda value: str(value).strip(),
|
|
35
|
+
validator=_validate_version,
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _resolve_version(version: str | None, interactive: bool | None, action: str) -> str:
|
|
42
|
+
values = resolve_command_inputs(
|
|
43
|
+
schema=VERSION_SCHEMA,
|
|
44
|
+
provided={"version": version},
|
|
45
|
+
interactive=interactive,
|
|
46
|
+
usage=f"Usage: chatup playwright {action} [VERSION] [-i|-I]",
|
|
47
|
+
)
|
|
48
|
+
return str(values["version"])
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _call(operation):
|
|
52
|
+
try:
|
|
53
|
+
return operation()
|
|
54
|
+
except backend.PlaywrightError as exc:
|
|
55
|
+
raise click.ClickException(str(exc)) from exc
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _emit(payload: dict[str, Any], output: str) -> None:
|
|
59
|
+
if output.lower() == "json":
|
|
60
|
+
click.echo(json.dumps(payload, indent=2, sort_keys=True))
|
|
61
|
+
return
|
|
62
|
+
for key, value in payload.items():
|
|
63
|
+
if value is not None:
|
|
64
|
+
click.echo(f"{key}: {value}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@click.group(name="playwright")
|
|
68
|
+
def cli() -> None:
|
|
69
|
+
"""Manage user-level Playwright browser installations."""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@cli.command(name="install")
|
|
73
|
+
@click.argument("version", required=False)
|
|
74
|
+
@click.option(
|
|
75
|
+
"--browser",
|
|
76
|
+
type=click.Choice(backend.SUPPORTED_BROWSERS, case_sensitive=False),
|
|
77
|
+
default="chromium",
|
|
78
|
+
show_default=True,
|
|
79
|
+
)
|
|
80
|
+
@click.option(
|
|
81
|
+
"--home",
|
|
82
|
+
type=click.Path(path_type=Path, file_okay=False),
|
|
83
|
+
default=backend.DEFAULT_HOME,
|
|
84
|
+
show_default=True,
|
|
85
|
+
)
|
|
86
|
+
@click.option("--force", is_flag=True, help="Atomically replace an existing installation.")
|
|
87
|
+
@click.option(
|
|
88
|
+
"--doctor/--no-doctor",
|
|
89
|
+
default=True,
|
|
90
|
+
show_default=True,
|
|
91
|
+
help="Probe the installed browser version.",
|
|
92
|
+
)
|
|
93
|
+
@click.option(
|
|
94
|
+
"--output",
|
|
95
|
+
type=click.Choice(OUTPUT_TYPES, case_sensitive=False),
|
|
96
|
+
default="text",
|
|
97
|
+
show_default=True,
|
|
98
|
+
)
|
|
99
|
+
@add_interactive_option
|
|
100
|
+
def install_command(
|
|
101
|
+
version: str | None,
|
|
102
|
+
browser: str,
|
|
103
|
+
home: Path,
|
|
104
|
+
force: bool,
|
|
105
|
+
doctor: bool,
|
|
106
|
+
output: str,
|
|
107
|
+
interactive: bool | None,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Install one exact Playwright package and browser."""
|
|
110
|
+
|
|
111
|
+
exact = _resolve_version(version, interactive, "install")
|
|
112
|
+
installation = _call(
|
|
113
|
+
lambda: backend.install(
|
|
114
|
+
exact,
|
|
115
|
+
browser=browser,
|
|
116
|
+
home=home,
|
|
117
|
+
force=force,
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
health = _call(lambda: backend.doctor(installation, execute=doctor))
|
|
121
|
+
_emit(health, output)
|
|
122
|
+
if health["status"] != "ready":
|
|
123
|
+
raise click.ClickException(
|
|
124
|
+
"Playwright installation is unhealthy: " + ", ".join(health["errors"])
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@cli.command(name="path")
|
|
129
|
+
@click.argument("version", required=False)
|
|
130
|
+
@click.option(
|
|
131
|
+
"--browser",
|
|
132
|
+
type=click.Choice(backend.SUPPORTED_BROWSERS, case_sensitive=False),
|
|
133
|
+
default="chromium",
|
|
134
|
+
show_default=True,
|
|
135
|
+
)
|
|
136
|
+
@click.option(
|
|
137
|
+
"--home",
|
|
138
|
+
type=click.Path(path_type=Path, file_okay=False),
|
|
139
|
+
default=backend.DEFAULT_HOME,
|
|
140
|
+
show_default=True,
|
|
141
|
+
)
|
|
142
|
+
@click.option(
|
|
143
|
+
"--output",
|
|
144
|
+
type=click.Choice(OUTPUT_TYPES, case_sensitive=False),
|
|
145
|
+
default="text",
|
|
146
|
+
show_default=True,
|
|
147
|
+
)
|
|
148
|
+
@add_interactive_option
|
|
149
|
+
def path_command(
|
|
150
|
+
version: str | None,
|
|
151
|
+
browser: str,
|
|
152
|
+
home: Path,
|
|
153
|
+
output: str,
|
|
154
|
+
interactive: bool | None,
|
|
155
|
+
) -> None:
|
|
156
|
+
"""Print the browser executable path for an installed Playwright version."""
|
|
157
|
+
|
|
158
|
+
exact = _resolve_version(version, interactive, "path")
|
|
159
|
+
installation = _call(
|
|
160
|
+
lambda: backend.resolve(exact, browser=browser, home=home)
|
|
161
|
+
)
|
|
162
|
+
if output.lower() == "json":
|
|
163
|
+
_emit(installation.to_dict(), output)
|
|
164
|
+
else:
|
|
165
|
+
click.echo(installation.binary_path)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@cli.command(name="doctor")
|
|
169
|
+
@click.argument("version", required=False)
|
|
170
|
+
@click.option(
|
|
171
|
+
"--browser",
|
|
172
|
+
type=click.Choice(backend.SUPPORTED_BROWSERS, case_sensitive=False),
|
|
173
|
+
default="chromium",
|
|
174
|
+
show_default=True,
|
|
175
|
+
)
|
|
176
|
+
@click.option(
|
|
177
|
+
"--home",
|
|
178
|
+
type=click.Path(path_type=Path, file_okay=False),
|
|
179
|
+
default=backend.DEFAULT_HOME,
|
|
180
|
+
show_default=True,
|
|
181
|
+
)
|
|
182
|
+
@click.option(
|
|
183
|
+
"--execute/--no-execute",
|
|
184
|
+
default=True,
|
|
185
|
+
show_default=True,
|
|
186
|
+
)
|
|
187
|
+
@click.option(
|
|
188
|
+
"--output",
|
|
189
|
+
type=click.Choice(OUTPUT_TYPES, case_sensitive=False),
|
|
190
|
+
default="text",
|
|
191
|
+
show_default=True,
|
|
192
|
+
)
|
|
193
|
+
@add_interactive_option
|
|
194
|
+
def doctor_command(
|
|
195
|
+
version: str | None,
|
|
196
|
+
browser: str,
|
|
197
|
+
home: Path,
|
|
198
|
+
execute: bool,
|
|
199
|
+
output: str,
|
|
200
|
+
interactive: bool | None,
|
|
201
|
+
) -> None:
|
|
202
|
+
"""Validate one installed Playwright browser."""
|
|
203
|
+
|
|
204
|
+
exact = _resolve_version(version, interactive, "doctor")
|
|
205
|
+
installation = _call(
|
|
206
|
+
lambda: backend.resolve(exact, browser=browser, home=home)
|
|
207
|
+
)
|
|
208
|
+
health = _call(lambda: backend.doctor(installation, execute=execute))
|
|
209
|
+
_emit(health, output)
|
|
210
|
+
if health["status"] != "ready":
|
|
211
|
+
raise click.ClickException(
|
|
212
|
+
"Playwright installation is unhealthy: " + ", ".join(health["errors"])
|
|
213
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from chatenv.fields import BaseEnvConfig, EnvField
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CursorAgentConfig(BaseEnvConfig):
|
|
7
|
+
"""ChatEnv schema for Cursor Agent credentials used by ChatUp setup."""
|
|
8
|
+
|
|
9
|
+
_title = "Cursor Agent"
|
|
10
|
+
_aliases = ["cursor-agent", "cursor_agent", "cursor"]
|
|
11
|
+
_storage_dir = "CursorAgent"
|
|
12
|
+
|
|
13
|
+
CURSOR_ACCESS_TOKEN = EnvField(
|
|
14
|
+
"CURSOR_ACCESS_TOKEN",
|
|
15
|
+
desc="Cursor Agent access token copied into Cursor auth.json by chatup cursor-agent.",
|
|
16
|
+
is_sensitive=True,
|
|
17
|
+
)
|
|
18
|
+
CURSOR_REFRESH_TOKEN = EnvField(
|
|
19
|
+
"CURSOR_REFRESH_TOKEN",
|
|
20
|
+
desc="Cursor Agent refresh token copied into Cursor auth.json by chatup cursor-agent.",
|
|
21
|
+
is_sensitive=True,
|
|
22
|
+
)
|
|
23
|
+
CURSOR_CREDENTIAL_STORE = EnvField(
|
|
24
|
+
"CURSOR_CREDENTIAL_STORE",
|
|
25
|
+
default="native",
|
|
26
|
+
desc="Cursor Agent credential store mode: native or file-wrapper.",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def test(cls) -> None:
|
|
31
|
+
"""Run a non-network schema smoke for chatenv test."""
|
|
32
|
+
|
|
33
|
+
print(f"Testing {cls._title}...")
|
|
34
|
+
fields = cls.get_fields()
|
|
35
|
+
expected = {
|
|
36
|
+
"CURSOR_ACCESS_TOKEN",
|
|
37
|
+
"CURSOR_REFRESH_TOKEN",
|
|
38
|
+
"CURSOR_CREDENTIAL_STORE",
|
|
39
|
+
}
|
|
40
|
+
missing = expected.difference(fields)
|
|
41
|
+
if missing:
|
|
42
|
+
raise RuntimeError(f"Missing Cursor Agent config field(s): {', '.join(sorted(missing))}")
|
|
43
|
+
if not fields["CURSOR_ACCESS_TOKEN"].is_sensitive or not fields["CURSOR_REFRESH_TOKEN"].is_sensitive:
|
|
44
|
+
raise RuntimeError("Cursor Agent token fields must be marked sensitive")
|
|
45
|
+
print("✓ Cursor Agent ChatEnv schema is registered.")
|
|
@@ -8,11 +8,27 @@ from chatstyle import (
|
|
|
8
8
|
add_interactive_option,
|
|
9
9
|
)
|
|
10
10
|
from chatstyle import resolve_command_inputs as _resolve_command_inputs
|
|
11
|
-
|
|
11
|
+
import chatstyle.tui.prompt as prompt_module
|
|
12
12
|
|
|
13
13
|
from .policy import resolve_interactive_mode
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def ask_confirm(*args, **kwargs):
|
|
17
|
+
return prompt_module.ask_confirm(*args, **kwargs)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def ask_path(*args, **kwargs):
|
|
21
|
+
return prompt_module.ask_path(*args, **kwargs)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ask_select(*args, **kwargs):
|
|
25
|
+
return prompt_module.ask_select(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ask_text(*args, **kwargs):
|
|
29
|
+
return prompt_module.ask_text(*args, **kwargs)
|
|
30
|
+
|
|
31
|
+
|
|
16
32
|
def resolve_command_inputs(*, schema, provided, interactive, usage):
|
|
17
33
|
"""Resolve command inputs through ChatStyle while preserving old patch points."""
|
|
18
34
|
|
|
@@ -27,10 +43,10 @@ def resolve_command_inputs(*, schema, provided, interactive, usage):
|
|
|
27
43
|
|
|
28
44
|
|
|
29
45
|
class _PromptRuntime:
|
|
30
|
-
ask_confirm = staticmethod(
|
|
31
|
-
ask_path = staticmethod(
|
|
32
|
-
ask_select = staticmethod(
|
|
33
|
-
ask_text = staticmethod(
|
|
46
|
+
ask_confirm = staticmethod(ask_confirm)
|
|
47
|
+
ask_path = staticmethod(ask_path)
|
|
48
|
+
ask_select = staticmethod(ask_select)
|
|
49
|
+
ask_text = staticmethod(ask_text)
|
|
34
50
|
|
|
35
51
|
|
|
36
52
|
def _resolve_interactive_for_chatstyle(*, interactive, auto_prompt_condition):
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"""Interactive policy helpers shared across CLI commands."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
|
|
3
5
|
import click
|
|
6
|
+
import chatstyle.core.interactive as interactive_module
|
|
4
7
|
|
|
5
8
|
from chatstyle import FORCE_INTERACTIVE_NO_TTY_MESSAGE
|
|
6
|
-
from chatstyle import is_interactive_available as _is_interactive_available
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
def is_interactive_available():
|
|
10
|
-
return
|
|
12
|
+
return interactive_module.is_interactive_available()
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def normalize_interactive(interactive):
|
|
@@ -24,11 +26,23 @@ def normalize_interactive(interactive):
|
|
|
24
26
|
return interactive
|
|
25
27
|
|
|
26
28
|
|
|
29
|
+
def _auto_prompt_enabled() -> bool:
|
|
30
|
+
value = os.environ.get("CHATARCH_AUTO_PROMPT")
|
|
31
|
+
if value is None:
|
|
32
|
+
return True
|
|
33
|
+
return value.strip().lower() not in {"0", "false", "no", "off"}
|
|
34
|
+
|
|
35
|
+
|
|
27
36
|
def resolve_interactive_mode(interactive, auto_prompt_condition):
|
|
28
37
|
interactive = normalize_interactive(interactive)
|
|
29
38
|
can_prompt = is_interactive_available()
|
|
30
39
|
force_interactive = interactive is True
|
|
31
|
-
auto_interactive =
|
|
40
|
+
auto_interactive = (
|
|
41
|
+
interactive is None
|
|
42
|
+
and can_prompt
|
|
43
|
+
and auto_prompt_condition
|
|
44
|
+
and _auto_prompt_enabled()
|
|
45
|
+
)
|
|
32
46
|
need_prompt = force_interactive or auto_interactive
|
|
33
47
|
return interactive, can_prompt, force_interactive, auto_interactive, need_prompt
|
|
34
48
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Public API for ChatArch-managed Playwright browsers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from chatup.runtime.playwright import (
|
|
9
|
+
DEFAULT_PLAYWRIGHT_HOME,
|
|
10
|
+
SUPPORTED_PLAYWRIGHT_BROWSERS,
|
|
11
|
+
PlaywrightBrowserInstallation,
|
|
12
|
+
PlaywrightError,
|
|
13
|
+
doctor_playwright_browser,
|
|
14
|
+
install_playwright_browser,
|
|
15
|
+
resolve_playwright_browser,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
DEFAULT_HOME = DEFAULT_PLAYWRIGHT_HOME
|
|
19
|
+
SUPPORTED_BROWSERS = SUPPORTED_PLAYWRIGHT_BROWSERS
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def install(
|
|
23
|
+
version: str,
|
|
24
|
+
*,
|
|
25
|
+
browser: str = "chromium",
|
|
26
|
+
home: Path | str | None = None,
|
|
27
|
+
force: bool = False,
|
|
28
|
+
) -> PlaywrightBrowserInstallation:
|
|
29
|
+
return install_playwright_browser(
|
|
30
|
+
version,
|
|
31
|
+
browser=browser,
|
|
32
|
+
home=home,
|
|
33
|
+
force=force,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def resolve(
|
|
38
|
+
version: str,
|
|
39
|
+
*,
|
|
40
|
+
browser: str = "chromium",
|
|
41
|
+
home: Path | str | None = None,
|
|
42
|
+
) -> PlaywrightBrowserInstallation:
|
|
43
|
+
return resolve_playwright_browser(version, browser=browser, home=home)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def doctor(
|
|
47
|
+
installation: PlaywrightBrowserInstallation,
|
|
48
|
+
*,
|
|
49
|
+
execute: bool = True,
|
|
50
|
+
) -> dict[str, Any]:
|
|
51
|
+
return doctor_playwright_browser(installation, execute=execute)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
__all__ = [
|
|
55
|
+
"DEFAULT_HOME",
|
|
56
|
+
"SUPPORTED_BROWSERS",
|
|
57
|
+
"PlaywrightBrowserInstallation",
|
|
58
|
+
"PlaywrightError",
|
|
59
|
+
"doctor",
|
|
60
|
+
"install",
|
|
61
|
+
"resolve",
|
|
62
|
+
]
|