arkclaw-webchat-cli 0.1.0__tar.gz → 0.2.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.
- arkclaw_webchat_cli-0.2.0/PKG-INFO +184 -0
- arkclaw_webchat_cli-0.2.0/README.md +160 -0
- {arkclaw_webchat_cli-0.1.0 → arkclaw_webchat_cli-0.2.0}/pyproject.toml +19 -2
- arkclaw_webchat_cli-0.2.0/src/ee_claw/attachments.py +81 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/cli.py +431 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/config.py +239 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/control.py +64 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/core.py +50 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/doctor.py +139 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/errors.py +132 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/flows.py +1220 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/identity.py +261 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/oauth.py +306 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/output.py +137 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/policy.py +63 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/providers.py +91 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/secrets_store.py +151 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/sts.py +154 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/transport/__init__.py +3 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/transport/a2a.py +399 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/transport/base.py +77 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/transport/openclaw.py +472 -0
- arkclaw_webchat_cli-0.2.0/src/ee_claw/update.py +74 -0
- arkclaw_webchat_cli-0.1.0/PKG-INFO +0 -87
- arkclaw_webchat_cli-0.1.0/README.md +0 -65
- arkclaw_webchat_cli-0.1.0/src/ee_claw/cli.py +0 -74
- arkclaw_webchat_cli-0.1.0/src/ee_claw/core.py +0 -472
- arkclaw_webchat_cli-0.1.0/tests/test_smoke.py +0 -41
- {arkclaw_webchat_cli-0.1.0 → arkclaw_webchat_cli-0.2.0}/.gitignore +0 -0
- {arkclaw_webchat_cli-0.1.0 → arkclaw_webchat_cli-0.2.0}/src/ee_claw/__init__.py +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arkclaw-webchat-cli
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: CLI to chat with an ArkClaw EE space's Claw over enterprise SSO — zero permanent AK/SK.
|
|
5
|
+
Author: ArkClaw Team
|
|
6
|
+
Keywords: arkclaw,cli,ee,openclaw,sso,sts
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Operating System :: MacOS
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: keyring>=24.0
|
|
17
|
+
Requires-Dist: typer>=0.12.0
|
|
18
|
+
Requires-Dist: websockets>=12.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
22
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# arkclaw
|
|
26
|
+
|
|
27
|
+
**Chat with your ArkClaw claws (agents) from the terminal — log in with your
|
|
28
|
+
own SSO identity, no passwords, no permanent keys.** Works the same for a human
|
|
29
|
+
at a prompt and for another agent/script (`--json` + exit codes).
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
arkclaw login https://your-space.arkclaw-enterprise-bj.volceapi.com # browser SSO, once
|
|
33
|
+
arkclaw agents # list the claws you can chat
|
|
34
|
+
arkclaw chat ci-xxxxxxxx # talk to one
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## What it can do
|
|
40
|
+
|
|
41
|
+
- **Log in as you** — browser SSO (PKCE), short-lived token, auto-refresh. No AK/SK, no client secret, nothing permanent on disk but a token in your OS keychain.
|
|
42
|
+
- **List your agents** — `arkclaw agents` shows the claws you can chat with.
|
|
43
|
+
- **Chat** — interactive REPL or one-shot `-m`, streaming token-by-token, with a live "what's it doing" spinner and tool-event trace.
|
|
44
|
+
- **Talk to a specific claw** — by id (`chat ci-...`) or by name (`chat 答疑助手`).
|
|
45
|
+
- **Manage a claw's files** — read/write its managed workspace files (`AGENTS.md`, `SOUL.md`, `MEMORY.md`, …) with `ls` / `pull` / `push`.
|
|
46
|
+
- **Fan out** — send one message to many claws in parallel.
|
|
47
|
+
- **Be scripted** — every command takes `--json` (one clean `{ok,data,error}` envelope on stdout) and returns a typed exit code.
|
|
48
|
+
|
|
49
|
+
Two transports, picked at login: **openclaw** (your claws, the default) and **a2a** (an agent endpoint).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install arkclaw-webchat-cli # provides the `arkclaw` command
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
From source:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
git clone <repo> && cd ee-claw
|
|
63
|
+
uv venv && uv pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Quick start
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 1. log in to your space (a browser opens; sign in with SSO)
|
|
72
|
+
arkclaw login https://your-space.arkclaw-enterprise-bj.volceapi.com
|
|
73
|
+
|
|
74
|
+
# 2. see which claws you can talk to
|
|
75
|
+
arkclaw agents
|
|
76
|
+
|
|
77
|
+
# 3. chat — interactive…
|
|
78
|
+
arkclaw chat ci-xxxxxxxx
|
|
79
|
+
# …or one-shot:
|
|
80
|
+
arkclaw chat ci-xxxxxxxx -m "用一句话介绍你自己"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`login` figures out the rest from the address (your identity pool, region). If
|
|
84
|
+
your space hasn't published auto-discovery yet, you may need to point it at the
|
|
85
|
+
STS role once — see **[Configuration](#configuration)**.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Commands
|
|
90
|
+
|
|
91
|
+
| Command | What it does |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `arkclaw login <space-url>` | Browser SSO login. `--transport a2a --endpoint <url>` for an agent endpoint. `--clawid ci-...` sets a default claw (otherwise the last one you opened in the browser). Bare `arkclaw login` re-logs into the previous space. |
|
|
94
|
+
| `arkclaw agents` | List the claws/agents you can chat with. |
|
|
95
|
+
| `arkclaw chat [TARGET] [MSG]` | Chat. `TARGET` = a claw id (`ci-...`), an agent name (from `agents`), or a profile. With `MSG` → one-shot; without → interactive REPL. `-f` attach files, `-o` write the reply, `--session NAME` name the conversation, `--approve-all` auto-approve tool runs. |
|
|
96
|
+
| `arkclaw <name>` | Shortcut: `arkclaw 答疑助手` ≡ `arkclaw chat 答疑助手`. |
|
|
97
|
+
| `arkclaw ls` | List the claw's managed workspace files. |
|
|
98
|
+
| `arkclaw pull <name> [local]` | Download a managed file to local disk. |
|
|
99
|
+
| `arkclaw push <local> [name]` | Write a local text file into a managed file. |
|
|
100
|
+
| `arkclaw fanout "<msg>" --clawid ci-a --clawid ci-b` | Same message to many claws in parallel. |
|
|
101
|
+
| `arkclaw sessions` | Recent chat sessions on this machine. |
|
|
102
|
+
| `arkclaw profile save/use/list` | Named snapshots of the session config (multi-space / multi-claw). |
|
|
103
|
+
| `arkclaw doctor` | Self-check: login freshness, keychain, pool/STS/endpoint reachability. |
|
|
104
|
+
| `arkclaw schema --json` | Machine-readable command surface (for agents/tooling). |
|
|
105
|
+
| `arkclaw claw list/describe/create/delete` | Fleet management on the control plane. |
|
|
106
|
+
|
|
107
|
+
All commands accept `--clawid ci-...` (where relevant) to target a specific claw, and `--json` for machine output.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Chatting
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
arkclaw chat ci-xxxx # REPL with that claw (Ctrl-C: interrupt turn; twice: exit)
|
|
115
|
+
arkclaw chat ci-xxxx -m "你好" # one-shot
|
|
116
|
+
arkclaw chat 答疑助手 -m "怎么部署" # by name (names come from `arkclaw agents`)
|
|
117
|
+
echo "$DATA" | arkclaw chat ci-xxxx --json -m "总结" | jq -r .data.reply # piped, machine
|
|
118
|
+
arkclaw chat ci-xxxx -f notes.md -m "review" -o out.md # attach context, save reply
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- **Streaming** on both transports; until the first token a spinner shows elapsed time + the running tool.
|
|
122
|
+
- **Sessions are server-side** — `--session NAME` keeps a named conversation that survives CLI restarts.
|
|
123
|
+
- **Tool approvals**: in a terminal you're prompted; headless it fails closed (deny) unless `--approve-all`; a `~/.arkclaw/cmdpolicy.json` deny-list always wins.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Files
|
|
128
|
+
|
|
129
|
+
`ls` / `pull` / `push` operate on a claw's **managed workspace files** — its
|
|
130
|
+
"brain": `AGENTS.md`, `SOUL.md`, `MEMORY.md`, `TOOLS.md`, `IDENTITY.md`,
|
|
131
|
+
`USER.md`, `HEARTBEAT.md`. (This is not a general file store — arbitrary
|
|
132
|
+
filenames are rejected.)
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
arkclaw ls # list them (defaults to your default claw)
|
|
136
|
+
arkclaw pull SOUL.md # download SOUL.md here
|
|
137
|
+
arkclaw pull AGENTS.md ./agents.md # download to a path
|
|
138
|
+
arkclaw push ./agents.md AGENTS.md # write a managed file
|
|
139
|
+
arkclaw ls --clawid ci-other # a different claw
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## For agents / automation
|
|
145
|
+
|
|
146
|
+
- `--json` → stdout is exactly one `{ok, data, error}` document; progress/streaming goes to stderr. Pipe to `jq`.
|
|
147
|
+
- Exit codes: `0` ok · `1` api · `2` validation · `3` auth · `4` network · `5` internal.
|
|
148
|
+
- Headless never blocks: `--json` / piped stdin refuse the interactive REPL; tool approvals fail closed.
|
|
149
|
+
- `arkclaw schema --json` describes every command + option for programmatic discovery.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Identity & security
|
|
154
|
+
|
|
155
|
+
- **Identity-through, zero permanent secrets.** Browser PKCE (S256, public client, loopback) → a short-lived `id_token` that *is your user identity* (same as the web app), auto-refreshed. The claw sees you, not a shared key.
|
|
156
|
+
- **openclaw** path exchanges that token (via a least-privilege STS role that can do exactly `GetClawInstanceChatToken`) for a one-time ChatToken, then connects over wss. **a2a** presents the token directly to the agent's gateway.
|
|
157
|
+
- Tokens live in the **OS keychain** (0600 file fallback). The config file holds only non-secret routing. Every upstream error is **redacted** (tokens / AK-SK) before display.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Configuration
|
|
162
|
+
|
|
163
|
+
`login` resolves config in this order: **explicit flag → `ARKCLAW_*` env →
|
|
164
|
+
the space's published discovery → derived from the address**. You normally only
|
|
165
|
+
type the address. Until your platform publishes auto-discovery, a deployment may
|
|
166
|
+
supply these (non-secret) via env:
|
|
167
|
+
|
|
168
|
+
| Env | Purpose |
|
|
169
|
+
|---|---|
|
|
170
|
+
| `ARKCLAW_CLIENT_ID` | The CLI's public OAuth client id for the pool. |
|
|
171
|
+
| `ARKCLAW_ROLE_TRN` | STS role that mints the ChatToken (openclaw). |
|
|
172
|
+
| `ARKCLAW_REGION` / `ARKCLAW_SPACE_ID` | Override region / space (usually auto). |
|
|
173
|
+
|
|
174
|
+
Other config: `~/.arkclaw/session.json` (routing, 0600), `~/.arkclaw/cmdpolicy.json` (tool-approval allow/deny), OS keychain (tokens).
|
|
175
|
+
|
|
176
|
+
> **Escape hatch (admin/test):** `arkclaw login <url> --transport openclaw --static-creds` uses `VOLCENGINE_ACCESS_KEY`/`SECRET_KEY` from the env instead of SSO — convenient for CI, but it's account-level keys, not identity-through.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Notes
|
|
181
|
+
|
|
182
|
+
- `ls`/`pull`/`push` and a bare `chat` use your **default claw** (set at login, or the last one you opened in the browser); override with `--clawid` (or `chat ci-...`).
|
|
183
|
+
- File commands cover the claw's **managed** files only; arbitrary file drop isn't exposed by the API.
|
|
184
|
+
- Nothing is hardcoded per space — the CLI reads what the space serves.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# arkclaw
|
|
2
|
+
|
|
3
|
+
**Chat with your ArkClaw claws (agents) from the terminal — log in with your
|
|
4
|
+
own SSO identity, no passwords, no permanent keys.** Works the same for a human
|
|
5
|
+
at a prompt and for another agent/script (`--json` + exit codes).
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
arkclaw login https://your-space.arkclaw-enterprise-bj.volceapi.com # browser SSO, once
|
|
9
|
+
arkclaw agents # list the claws you can chat
|
|
10
|
+
arkclaw chat ci-xxxxxxxx # talk to one
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What it can do
|
|
16
|
+
|
|
17
|
+
- **Log in as you** — browser SSO (PKCE), short-lived token, auto-refresh. No AK/SK, no client secret, nothing permanent on disk but a token in your OS keychain.
|
|
18
|
+
- **List your agents** — `arkclaw agents` shows the claws you can chat with.
|
|
19
|
+
- **Chat** — interactive REPL or one-shot `-m`, streaming token-by-token, with a live "what's it doing" spinner and tool-event trace.
|
|
20
|
+
- **Talk to a specific claw** — by id (`chat ci-...`) or by name (`chat 答疑助手`).
|
|
21
|
+
- **Manage a claw's files** — read/write its managed workspace files (`AGENTS.md`, `SOUL.md`, `MEMORY.md`, …) with `ls` / `pull` / `push`.
|
|
22
|
+
- **Fan out** — send one message to many claws in parallel.
|
|
23
|
+
- **Be scripted** — every command takes `--json` (one clean `{ok,data,error}` envelope on stdout) and returns a typed exit code.
|
|
24
|
+
|
|
25
|
+
Two transports, picked at login: **openclaw** (your claws, the default) and **a2a** (an agent endpoint).
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install arkclaw-webchat-cli # provides the `arkclaw` command
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
From source:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone <repo> && cd ee-claw
|
|
39
|
+
uv venv && uv pip install -e .
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Quick start
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# 1. log in to your space (a browser opens; sign in with SSO)
|
|
48
|
+
arkclaw login https://your-space.arkclaw-enterprise-bj.volceapi.com
|
|
49
|
+
|
|
50
|
+
# 2. see which claws you can talk to
|
|
51
|
+
arkclaw agents
|
|
52
|
+
|
|
53
|
+
# 3. chat — interactive…
|
|
54
|
+
arkclaw chat ci-xxxxxxxx
|
|
55
|
+
# …or one-shot:
|
|
56
|
+
arkclaw chat ci-xxxxxxxx -m "用一句话介绍你自己"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`login` figures out the rest from the address (your identity pool, region). If
|
|
60
|
+
your space hasn't published auto-discovery yet, you may need to point it at the
|
|
61
|
+
STS role once — see **[Configuration](#configuration)**.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Commands
|
|
66
|
+
|
|
67
|
+
| Command | What it does |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `arkclaw login <space-url>` | Browser SSO login. `--transport a2a --endpoint <url>` for an agent endpoint. `--clawid ci-...` sets a default claw (otherwise the last one you opened in the browser). Bare `arkclaw login` re-logs into the previous space. |
|
|
70
|
+
| `arkclaw agents` | List the claws/agents you can chat with. |
|
|
71
|
+
| `arkclaw chat [TARGET] [MSG]` | Chat. `TARGET` = a claw id (`ci-...`), an agent name (from `agents`), or a profile. With `MSG` → one-shot; without → interactive REPL. `-f` attach files, `-o` write the reply, `--session NAME` name the conversation, `--approve-all` auto-approve tool runs. |
|
|
72
|
+
| `arkclaw <name>` | Shortcut: `arkclaw 答疑助手` ≡ `arkclaw chat 答疑助手`. |
|
|
73
|
+
| `arkclaw ls` | List the claw's managed workspace files. |
|
|
74
|
+
| `arkclaw pull <name> [local]` | Download a managed file to local disk. |
|
|
75
|
+
| `arkclaw push <local> [name]` | Write a local text file into a managed file. |
|
|
76
|
+
| `arkclaw fanout "<msg>" --clawid ci-a --clawid ci-b` | Same message to many claws in parallel. |
|
|
77
|
+
| `arkclaw sessions` | Recent chat sessions on this machine. |
|
|
78
|
+
| `arkclaw profile save/use/list` | Named snapshots of the session config (multi-space / multi-claw). |
|
|
79
|
+
| `arkclaw doctor` | Self-check: login freshness, keychain, pool/STS/endpoint reachability. |
|
|
80
|
+
| `arkclaw schema --json` | Machine-readable command surface (for agents/tooling). |
|
|
81
|
+
| `arkclaw claw list/describe/create/delete` | Fleet management on the control plane. |
|
|
82
|
+
|
|
83
|
+
All commands accept `--clawid ci-...` (where relevant) to target a specific claw, and `--json` for machine output.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Chatting
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
arkclaw chat ci-xxxx # REPL with that claw (Ctrl-C: interrupt turn; twice: exit)
|
|
91
|
+
arkclaw chat ci-xxxx -m "你好" # one-shot
|
|
92
|
+
arkclaw chat 答疑助手 -m "怎么部署" # by name (names come from `arkclaw agents`)
|
|
93
|
+
echo "$DATA" | arkclaw chat ci-xxxx --json -m "总结" | jq -r .data.reply # piped, machine
|
|
94
|
+
arkclaw chat ci-xxxx -f notes.md -m "review" -o out.md # attach context, save reply
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- **Streaming** on both transports; until the first token a spinner shows elapsed time + the running tool.
|
|
98
|
+
- **Sessions are server-side** — `--session NAME` keeps a named conversation that survives CLI restarts.
|
|
99
|
+
- **Tool approvals**: in a terminal you're prompted; headless it fails closed (deny) unless `--approve-all`; a `~/.arkclaw/cmdpolicy.json` deny-list always wins.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Files
|
|
104
|
+
|
|
105
|
+
`ls` / `pull` / `push` operate on a claw's **managed workspace files** — its
|
|
106
|
+
"brain": `AGENTS.md`, `SOUL.md`, `MEMORY.md`, `TOOLS.md`, `IDENTITY.md`,
|
|
107
|
+
`USER.md`, `HEARTBEAT.md`. (This is not a general file store — arbitrary
|
|
108
|
+
filenames are rejected.)
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
arkclaw ls # list them (defaults to your default claw)
|
|
112
|
+
arkclaw pull SOUL.md # download SOUL.md here
|
|
113
|
+
arkclaw pull AGENTS.md ./agents.md # download to a path
|
|
114
|
+
arkclaw push ./agents.md AGENTS.md # write a managed file
|
|
115
|
+
arkclaw ls --clawid ci-other # a different claw
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## For agents / automation
|
|
121
|
+
|
|
122
|
+
- `--json` → stdout is exactly one `{ok, data, error}` document; progress/streaming goes to stderr. Pipe to `jq`.
|
|
123
|
+
- Exit codes: `0` ok · `1` api · `2` validation · `3` auth · `4` network · `5` internal.
|
|
124
|
+
- Headless never blocks: `--json` / piped stdin refuse the interactive REPL; tool approvals fail closed.
|
|
125
|
+
- `arkclaw schema --json` describes every command + option for programmatic discovery.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Identity & security
|
|
130
|
+
|
|
131
|
+
- **Identity-through, zero permanent secrets.** Browser PKCE (S256, public client, loopback) → a short-lived `id_token` that *is your user identity* (same as the web app), auto-refreshed. The claw sees you, not a shared key.
|
|
132
|
+
- **openclaw** path exchanges that token (via a least-privilege STS role that can do exactly `GetClawInstanceChatToken`) for a one-time ChatToken, then connects over wss. **a2a** presents the token directly to the agent's gateway.
|
|
133
|
+
- Tokens live in the **OS keychain** (0600 file fallback). The config file holds only non-secret routing. Every upstream error is **redacted** (tokens / AK-SK) before display.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Configuration
|
|
138
|
+
|
|
139
|
+
`login` resolves config in this order: **explicit flag → `ARKCLAW_*` env →
|
|
140
|
+
the space's published discovery → derived from the address**. You normally only
|
|
141
|
+
type the address. Until your platform publishes auto-discovery, a deployment may
|
|
142
|
+
supply these (non-secret) via env:
|
|
143
|
+
|
|
144
|
+
| Env | Purpose |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `ARKCLAW_CLIENT_ID` | The CLI's public OAuth client id for the pool. |
|
|
147
|
+
| `ARKCLAW_ROLE_TRN` | STS role that mints the ChatToken (openclaw). |
|
|
148
|
+
| `ARKCLAW_REGION` / `ARKCLAW_SPACE_ID` | Override region / space (usually auto). |
|
|
149
|
+
|
|
150
|
+
Other config: `~/.arkclaw/session.json` (routing, 0600), `~/.arkclaw/cmdpolicy.json` (tool-approval allow/deny), OS keychain (tokens).
|
|
151
|
+
|
|
152
|
+
> **Escape hatch (admin/test):** `arkclaw login <url> --transport openclaw --static-creds` uses `VOLCENGINE_ACCESS_KEY`/`SECRET_KEY` from the env instead of SSO — convenient for CI, but it's account-level keys, not identity-through.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Notes
|
|
157
|
+
|
|
158
|
+
- `ls`/`pull`/`push` and a bare `chat` use your **default claw** (set at login, or the last one you opened in the browser); override with `--clawid` (or `chat ci-...`).
|
|
159
|
+
- File commands cover the claw's **managed** files only; arbitrary file drop isn't exposed by the API.
|
|
160
|
+
- Nothing is hardcoded per space — the CLI reads what the space serves.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "arkclaw-webchat-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "CLI to chat with an ArkClaw EE space's Claw over enterprise SSO — zero permanent AK/SK."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -23,20 +23,28 @@ classifiers = [
|
|
|
23
23
|
dependencies = [
|
|
24
24
|
"typer>=0.12.0",
|
|
25
25
|
"websockets>=12.0",
|
|
26
|
+
"keyring>=24.0",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
[project.optional-dependencies]
|
|
29
30
|
dev = [
|
|
30
31
|
"pytest>=7.4",
|
|
31
32
|
"ruff>=0.6",
|
|
33
|
+
"mypy>=1.10",
|
|
32
34
|
]
|
|
33
35
|
|
|
34
36
|
[project.scripts]
|
|
35
|
-
arkclaw
|
|
37
|
+
arkclaw = "ee_claw.cli:main"
|
|
38
|
+
arkclaw-webchat = "ee_claw.cli:main" # legacy alias
|
|
36
39
|
|
|
37
40
|
[tool.hatch.build.targets.wheel]
|
|
38
41
|
packages = ["src/ee_claw"]
|
|
39
42
|
|
|
43
|
+
[tool.hatch.build.targets.sdist]
|
|
44
|
+
# Ship ONLY the package (+ auto: pyproject, README). Never publish the internal
|
|
45
|
+
# docs/ (SRE asks, well-known sample) — they carry real deployment identifiers.
|
|
46
|
+
only-include = ["src/ee_claw"]
|
|
47
|
+
|
|
40
48
|
[tool.ruff]
|
|
41
49
|
line-length = 100
|
|
42
50
|
target-version = "py310"
|
|
@@ -45,3 +53,12 @@ src = ["src", "tests"]
|
|
|
45
53
|
[tool.ruff.lint]
|
|
46
54
|
select = ["E", "W", "F", "I", "UP", "B"]
|
|
47
55
|
ignore = ["E501"]
|
|
56
|
+
|
|
57
|
+
[tool.ruff.lint.per-file-ignores]
|
|
58
|
+
# typer's API *is* function calls in argument defaults.
|
|
59
|
+
"src/ee_claw/cli.py" = ["B008"]
|
|
60
|
+
|
|
61
|
+
[tool.mypy]
|
|
62
|
+
python_version = "3.10"
|
|
63
|
+
ignore_missing_imports = true
|
|
64
|
+
check_untyped_defs = true
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Composable input: collect stdin / files / directories into Attachments.
|
|
2
|
+
|
|
3
|
+
Caps are explicit and every drop is reported (no silent truncation — a "we
|
|
4
|
+
covered everything" that didn't is worse than a visible limit)."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import mimetypes
|
|
9
|
+
import pathlib
|
|
10
|
+
|
|
11
|
+
from ee_claw.errors import ValidationError
|
|
12
|
+
from ee_claw.transport.base import Attachment
|
|
13
|
+
|
|
14
|
+
MAX_FILE_BYTES = 64 * 1024
|
|
15
|
+
MAX_TOTAL_BYTES = 256 * 1024
|
|
16
|
+
MAX_FILES = 32
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def collect_files(paths: list[str]) -> tuple[list[Attachment], list[str]]:
|
|
20
|
+
"""Read files (and directories, shallow-recursively) into attachments.
|
|
21
|
+
Returns ``(attachments, notices)`` — notices describe everything that was
|
|
22
|
+
truncated or skipped, for the human stream."""
|
|
23
|
+
notices: list[str] = []
|
|
24
|
+
candidates: list[pathlib.Path] = []
|
|
25
|
+
for raw in paths:
|
|
26
|
+
p = pathlib.Path(raw).expanduser()
|
|
27
|
+
if not p.exists():
|
|
28
|
+
raise ValidationError(f"文件不存在: {raw}")
|
|
29
|
+
if p.is_dir():
|
|
30
|
+
# Exclude any path with a hidden COMPONENT below the requested dir
|
|
31
|
+
# (not just hidden leaves): rglob descends into .git/ and .ssh/,
|
|
32
|
+
# whose contents are exactly the secrets that must never ride
|
|
33
|
+
# along. relative_to(p) keeps a user-supplied hidden base
|
|
34
|
+
# (e.g. -f ~/.config/proj) workable.
|
|
35
|
+
inner = sorted(
|
|
36
|
+
f
|
|
37
|
+
for f in p.rglob("*")
|
|
38
|
+
if f.is_file()
|
|
39
|
+
and not any(part.startswith(".") for part in f.relative_to(p).parts)
|
|
40
|
+
)
|
|
41
|
+
candidates.extend(inner)
|
|
42
|
+
else:
|
|
43
|
+
candidates.append(p)
|
|
44
|
+
|
|
45
|
+
if len(candidates) > MAX_FILES:
|
|
46
|
+
notices.append(f"超出 {MAX_FILES} 个文件上限,丢弃了 {len(candidates) - MAX_FILES} 个")
|
|
47
|
+
candidates = candidates[:MAX_FILES]
|
|
48
|
+
|
|
49
|
+
attachments: list[Attachment] = []
|
|
50
|
+
total = 0
|
|
51
|
+
for f in candidates:
|
|
52
|
+
try:
|
|
53
|
+
content = f.read_bytes()
|
|
54
|
+
except OSError as e:
|
|
55
|
+
notices.append(f"读不了 {f}: {e.__class__.__name__}")
|
|
56
|
+
continue
|
|
57
|
+
if len(content) > MAX_FILE_BYTES:
|
|
58
|
+
notices.append(f"{f.name} 截断到 {MAX_FILE_BYTES // 1024}KB(原 {len(content)} 字节)")
|
|
59
|
+
content = content[:MAX_FILE_BYTES]
|
|
60
|
+
if total + len(content) > MAX_TOTAL_BYTES:
|
|
61
|
+
notices.append(f"总量超出 {MAX_TOTAL_BYTES // 1024}KB,从 {f.name} 起丢弃")
|
|
62
|
+
break
|
|
63
|
+
total += len(content)
|
|
64
|
+
mime = mimetypes.guess_type(f.name)[0] or "application/octet-stream"
|
|
65
|
+
attachments.append(Attachment(name=f.name, content=content, mime=mime))
|
|
66
|
+
return attachments, notices
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def inline_attachments(message: str, files: tuple[Attachment, ...] | list[Attachment]) -> tuple[str, list[str]]:
|
|
70
|
+
"""Render text attachments as context blocks appended to the message (for
|
|
71
|
+
transports without native file parts). Returns ``(message, skipped_names)``
|
|
72
|
+
— binary attachments can't be inlined and are reported, not dropped silently."""
|
|
73
|
+
blocks = [message]
|
|
74
|
+
skipped: list[str] = []
|
|
75
|
+
for att in files:
|
|
76
|
+
text = att.text
|
|
77
|
+
if text is None:
|
|
78
|
+
skipped.append(att.name)
|
|
79
|
+
continue
|
|
80
|
+
blocks.append(f"\n\n--- 文件: {att.name} ---\n{text}")
|
|
81
|
+
return "".join(blocks), skipped
|