arkclaw-webchat-cli 0.9.0__tar.gz → 0.13.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.
Files changed (31) hide show
  1. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/PKG-INFO +55 -19
  2. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/README.md +54 -18
  3. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/pyproject.toml +1 -1
  4. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/cli.py +210 -60
  5. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/flows.py +551 -96
  6. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/identity.py +40 -0
  7. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/netdisk.py +57 -12
  8. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/openclaw.py +57 -0
  9. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/.gitignore +0 -0
  10. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/__init__.py +0 -0
  11. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/attachments.py +0 -0
  12. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/config.py +0 -0
  13. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/control.py +0 -0
  14. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/core.py +0 -0
  15. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/doctor.py +0 -0
  16. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/errors.py +0 -0
  17. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/oauth.py +0 -0
  18. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/output.py +0 -0
  19. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/policy.py +0 -0
  20. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/providers.py +0 -0
  21. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/secrets_store.py +0 -0
  22. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/sts.py +0 -0
  23. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/terminal_io.py +0 -0
  24. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/__init__.py +0 -0
  25. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/a2a.py +0 -0
  26. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/base.py +0 -0
  27. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/claw_terminal.py +0 -0
  28. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/silk.py +0 -0
  29. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/silk_fs.py +0 -0
  30. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/transport/silk_rpc.py +0 -0
  31. {arkclaw_webchat_cli-0.9.0 → arkclaw_webchat_cli-0.13.0}/src/ee_claw/update.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arkclaw-webchat-cli
3
- Version: 0.9.0
3
+ Version: 0.13.0
4
4
  Summary: CLI to chat with an ArkClaw EE space's Claw over enterprise SSO — zero permanent AK/SK.
5
5
  Author: ArkClaw Team
6
6
  Keywords: arkclaw,cli,ee,openclaw,sso,sts
@@ -49,6 +49,7 @@ arkclaw chat ci-xxxxxxxx
49
49
  - **Upload & download any file** — push arbitrary files into the claw's *real* workspace filesystem and pull results back (a whole directory comes as a `.tar`) with `upload` / `download` / `mkdir` / `ls <path>`, over the Silk file service (needs a Silk-enabled claw).
50
50
  - **Large-product storage** — a separate IDS *netdisk* plane for big artifacts/videos: `netdisk create-space` / `ls` / `upload` / `download` / `mkdir` / `rm`.
51
51
  - **Read past conversations** — list an agent's sessions, then pull a full transcript with `arkclaw history <会话ID>` (over the `chat.history` ws RPC; `--json` to export, `-o` to a file).
52
+ - **Schedule tasks** — `arkclaw cron` makes the claw run a prompt unattended on a cron expression / fixed interval / one-shot time (`add` / `list` / `run` / `runs` / `update` / `rm`), over the runtime's `cron.*` RPCs.
52
53
  - **Fan out** — send one message to many claws in parallel.
53
54
  - **Be scripted** — every command takes `--json` (one clean `{ok,data,error}` envelope on stdout) and returns a typed exit code.
54
55
 
@@ -118,14 +119,14 @@ straight to `arkclaw login https://your-space...`. See **[Configuration](#config
118
119
  | `arkclaw upload <local> [remote]` | Upload **any** file into the claw's workspace filesystem (Silk). Defaults to the basename at the workspace root. |
119
120
  | `arkclaw download <remote> [local]` | Download a workspace file from the claw (Silk); a directory comes as `<name>.tar`. |
120
121
  | `arkclaw mkdir <path>` | Create a directory in the claw workspace (Silk; parent must exist). |
121
- | `arkclaw netdisk <cmd>` | IDS netdisk (large products/videos), a separate storage plane: `create-space` / `ls` / `upload` / `download` / `mkdir` / `rm`. Configured via `IDS_*` env. |
122
+ | `arkclaw netdisk <cmd>` | IDS netdisk (large products/videos), a separate storage plane: `create-space` / `ls` / `upload` / `download` / `mkdir` / `rm`. Per-user creds minted from your SSO login (no static AK/SK). |
122
123
  | `arkclaw fanout "<msg>" --clawid ci-a --clawid ci-b` | Same message to many claws in parallel. |
123
124
  | `arkclaw sessions [claw]` | An agent's conversations from the server (`--agent` to pick one), newest first — resume with `chat --session <会话ID>`, read with `history <会话ID>`, fork with `--new`. Falls back to the local record when offline / a2a. |
124
- | `arkclaw history <session>` | Print a past conversation's full transcript (ws `chat.history`). `<session>` = a 会话ID from `sessions`, a label, or a full `agent:…` key. Tool steps hidden unless `--show-tools`; `--json` dumps every message; `-o` writes a plain-text log. openclaw only. |
125
+ | `arkclaw history <session>` | Print a past conversation's transcript (ws `chat.history`). `<session>` = a 会话ID from `sessions`, a label, or a full `agent:…` key. The screen shows the last `--tail N` messages (default 50; `--all` for everything); tool steps hidden unless `--show-tools`; `--json` dumps every message; `-o` writes a plain-text log. openclaw only. |
126
+ | `arkclaw cron <cmd>` | Scheduled tasks the claw runs unattended (ws `cron.*`): `status` (is the scheduler on), `list`, `get <id>`, `add --name … (--cron EXPR \| --every DUR \| --at TIME) -m "<prompt>"`, `update <id>`, `run <id>` (fire now), `runs [id]` (history), `rm <id>`. Needs a claw whose runtime has the scheduler enabled (`cron status`). openclaw only. |
125
127
  | `arkclaw profile save/use/list` | Named snapshots of the session config (multi-space / multi-claw). |
126
128
  | `arkclaw doctor` | Self-check: login freshness, keychain, pool/STS/endpoint reachability. |
127
129
  | `arkclaw schema --json` | Machine-readable command surface (for agents/tooling). |
128
- | `arkclaw claw list/describe/create/delete` | Fleet management on the control plane. |
129
130
 
130
131
  All commands accept `--clawid ci-...` (where relevant) to target a specific claw, and `--json` for machine output.
131
132
 
@@ -155,7 +156,7 @@ The CLI moves files across **three distinct planes** — pick by what you're car
155
156
  |---|---|---|
156
157
  | **Managed brain** | `ls` · `pull` · `push` | The claw's own config files (`AGENTS.md`, `SOUL.md`, …). A fixed allow-list, not a general store. |
157
158
  | **Workspace (Silk)** | `ls <path>` · `upload` · `download` · `mkdir` | The claw's *real* working filesystem — arbitrary files, uploads, agent outputs, subdirectories. |
158
- | **Netdisk (IDS)** | `netdisk …` | A separate large-object store for big products/videos, on a dedicated storage account. |
159
+ | **Netdisk (IDS)** | `netdisk …` | A separate large-object store for big products/videos; per-user creds minted from your SSO login. |
159
160
 
160
161
  ### 1. Managed brain files — `ls` / `pull` / `push`
161
162
 
@@ -195,26 +196,58 @@ arkclaw download runs ./runs.tar # a directory downloads as a .tar
195
196
 
196
197
  ### 3. Netdisk (IDS) — `netdisk …`
197
198
 
198
- A separate storage plane for large products/videos, on a **dedicated IDS
199
- account** (not your SSO identity). Configured entirely from `IDS_*` env vars
200
- (provisioned by the storage team). Create a space once, then pass its `SpaceID`:
199
+ A separate storage plane for large products/videos. Credentials are **minted
200
+ per-user from your SSO login** no static AK/SK: the claw's iDrive instance is
201
+ resolved and a minimal-permission temp credential is issued for *your*
202
+ `UserPoolUserUid` (`GetIDriveInstance` → `GetIDriveCredential`). `--space`
203
+ defaults to the claw's iDrive space; pass it to target another.
201
204
 
202
205
  ```bash
203
- arkclaw netdisk create-space my-space # prints the SpaceID
204
- arkclaw netdisk mkdir outputs --space spc-...
205
- arkclaw netdisk upload ./final.mp4 outputs/final.mp4 --space spc-...
206
- arkclaw netdisk ls outputs/ --space spc-...
207
- arkclaw netdisk download outputs/final.mp4 ./final.mp4 --space spc-...
208
- arkclaw netdisk rm outputs/final.mp4 --space spc-... # asks unless --yes
206
+ arkclaw netdisk ls # the claw's iDrive space
207
+ arkclaw netdisk upload ./final.mp4 outputs/final.mp4
208
+ arkclaw netdisk download outputs/final.mp4 ./final.mp4
209
+ arkclaw netdisk mkdir outputs
210
+ arkclaw netdisk rm outputs/final.mp4 # asks unless --yes
211
+ arkclaw netdisk create-space my-space # a second space prints its SpaceID
212
+ arkclaw netdisk ls --space spc-... # target a specific space
209
213
  ```
210
214
 
211
215
  `create-space` also takes `--description`; `ls` takes `--limit N` to cap entries.
212
216
 
217
+ For CI / a dedicated storage account you can still override the identity path:
218
+
213
219
  | Env | Purpose |
214
220
  |---|---|
215
- | `IDS_BASE_URL` / `IDS_REGION` / `IDS_SERVICE` / `IDS_INSTANCE_ID` | Endpoint + routing for the IDS instance. |
216
- | `IDS_AK` / `IDS_SK` (+ `IDS_ACCOUNT_ID`) | Static credentials for the storage account |
217
- | `IDS_ROLE_TRN` | …or assume a role via SSO instead of static AK/SK. |
221
+ | `IDS_ROLE_TRN` (+ `IDS_BASE_URL` / `IDS_REGION` / `IDS_SERVICE` / `IDS_INSTANCE_ID`) | Assume an IDS role via SSO instead. |
222
+ | `IDS_AK` / `IDS_SK` (+ `IDS_ACCOUNT_ID`, endpoint/routing vars) | Static credentials for a dedicated storage account. |
223
+
224
+ ---
225
+
226
+ ## Scheduled tasks — `cron`
227
+
228
+ Let a claw run a prompt **unattended** on a schedule (its runtime carries a
229
+ scheduler; check it with `arkclaw cron status`). A task is an *agent turn* — the
230
+ `--message` is the prompt the agent runs at each fire.
231
+
232
+ ```bash
233
+ arkclaw cron status # is the scheduler on; jobs; next wake
234
+ arkclaw cron add --name 早报 \
235
+ --cron "0 9 * * *" --tz Asia/Shanghai \
236
+ -m "联网搜集今天的科技新闻,生成一份中文摘要" # every day 09:00
237
+ arkclaw cron add --name 巡检 --every 30m -m "检查服务健康并报告异常"
238
+ arkclaw cron add --name 一次性 --at 2026-07-01T09:00:00+08:00 -m "提醒我项目截止" --delete-after-run
239
+ arkclaw cron list # all jobs (enabled + disabled)
240
+ arkclaw cron run <id> # fire one now (server-side)
241
+ arkclaw cron runs <id> # recent run history + status
242
+ arkclaw cron update <id> --disable # pause; --enable to resume
243
+ arkclaw cron rm <id> # delete (asks unless --yes)
244
+ ```
245
+
246
+ Schedule is exactly one of `--cron "<expr>"` (with optional `--tz`), `--every
247
+ <30s|15m|2h|1d>`, or `--at <ISO8601>`. `--session-target` picks where the run
248
+ lives (`isolated` default / `main` / `current`); `--agent` runs it as a specific
249
+ agent. Jobs the platform manages (created by an agent-pack template) are marked
250
+ `*` in the list — edit those in the console, not here. openclaw plane only.
218
251
 
219
252
  ---
220
253
 
@@ -238,8 +271,10 @@ arkclaw netdisk rm outputs/final.mp4 --space spc-... # asks unless --yes
238
271
  ## Configuration
239
272
 
240
273
  `login` resolves config in this order: **explicit flag → `ARKCLAW_*` env →
241
- the space's published discovery → `arkclaw init` defaults → derived from the
242
- address**. You normally only type the address.
274
+ the space's discovery → `arkclaw init` defaults → derived from the address**.
275
+ You normally only type the address — when the space exposes the CLI bootstrap
276
+ endpoint, `login` auto-fetches its public OAuth client + STS role, so even
277
+ `--client-id` / `--role-trn` are optional.
243
278
 
244
279
  **The easy way — `arkclaw init`** asks once (interactively) for whatever the
245
280
  space doesn't yet auto-publish, and saves it. After that, just `arkclaw login`.
@@ -253,6 +288,7 @@ values via env:
253
288
  | `ARKCLAW_ROLE_TRN` | STS role that mints the ChatToken (openclaw). |
254
289
  | `ARKCLAW_REGION` / `ARKCLAW_SPACE_ID` | Override region / space (usually auto). |
255
290
  | `ARKCLAW_API_HOST` / `ARKCLAW_API_SERVICE` | **Advanced/testing.** Point the control-plane calls at a non-production plane (host + SigV4 service). See the note below. |
291
+ | `ARKCLAW_FORWARD_ENV` | **Advanced/non-prod.** Adds an `X-Forward-Env` header to the space's CLI-bootstrap call to route to a small-traffic gateway. Unset (production) sends no header. |
256
292
 
257
293
  Other config: `~/.arkclaw/defaults.json` (`init` answers, 0600), `~/.arkclaw/session.json` (routing, 0600), `~/.arkclaw/cmdpolicy.json` (tool-approval allow/deny), OS keychain (tokens).
258
294
 
@@ -24,6 +24,7 @@ arkclaw chat ci-xxxxxxxx
24
24
  - **Upload & download any file** — push arbitrary files into the claw's *real* workspace filesystem and pull results back (a whole directory comes as a `.tar`) with `upload` / `download` / `mkdir` / `ls <path>`, over the Silk file service (needs a Silk-enabled claw).
25
25
  - **Large-product storage** — a separate IDS *netdisk* plane for big artifacts/videos: `netdisk create-space` / `ls` / `upload` / `download` / `mkdir` / `rm`.
26
26
  - **Read past conversations** — list an agent's sessions, then pull a full transcript with `arkclaw history <会话ID>` (over the `chat.history` ws RPC; `--json` to export, `-o` to a file).
27
+ - **Schedule tasks** — `arkclaw cron` makes the claw run a prompt unattended on a cron expression / fixed interval / one-shot time (`add` / `list` / `run` / `runs` / `update` / `rm`), over the runtime's `cron.*` RPCs.
27
28
  - **Fan out** — send one message to many claws in parallel.
28
29
  - **Be scripted** — every command takes `--json` (one clean `{ok,data,error}` envelope on stdout) and returns a typed exit code.
29
30
 
@@ -93,14 +94,14 @@ straight to `arkclaw login https://your-space...`. See **[Configuration](#config
93
94
  | `arkclaw upload <local> [remote]` | Upload **any** file into the claw's workspace filesystem (Silk). Defaults to the basename at the workspace root. |
94
95
  | `arkclaw download <remote> [local]` | Download a workspace file from the claw (Silk); a directory comes as `<name>.tar`. |
95
96
  | `arkclaw mkdir <path>` | Create a directory in the claw workspace (Silk; parent must exist). |
96
- | `arkclaw netdisk <cmd>` | IDS netdisk (large products/videos), a separate storage plane: `create-space` / `ls` / `upload` / `download` / `mkdir` / `rm`. Configured via `IDS_*` env. |
97
+ | `arkclaw netdisk <cmd>` | IDS netdisk (large products/videos), a separate storage plane: `create-space` / `ls` / `upload` / `download` / `mkdir` / `rm`. Per-user creds minted from your SSO login (no static AK/SK). |
97
98
  | `arkclaw fanout "<msg>" --clawid ci-a --clawid ci-b` | Same message to many claws in parallel. |
98
99
  | `arkclaw sessions [claw]` | An agent's conversations from the server (`--agent` to pick one), newest first — resume with `chat --session <会话ID>`, read with `history <会话ID>`, fork with `--new`. Falls back to the local record when offline / a2a. |
99
- | `arkclaw history <session>` | Print a past conversation's full transcript (ws `chat.history`). `<session>` = a 会话ID from `sessions`, a label, or a full `agent:…` key. Tool steps hidden unless `--show-tools`; `--json` dumps every message; `-o` writes a plain-text log. openclaw only. |
100
+ | `arkclaw history <session>` | Print a past conversation's transcript (ws `chat.history`). `<session>` = a 会话ID from `sessions`, a label, or a full `agent:…` key. The screen shows the last `--tail N` messages (default 50; `--all` for everything); tool steps hidden unless `--show-tools`; `--json` dumps every message; `-o` writes a plain-text log. openclaw only. |
101
+ | `arkclaw cron <cmd>` | Scheduled tasks the claw runs unattended (ws `cron.*`): `status` (is the scheduler on), `list`, `get <id>`, `add --name … (--cron EXPR \| --every DUR \| --at TIME) -m "<prompt>"`, `update <id>`, `run <id>` (fire now), `runs [id]` (history), `rm <id>`. Needs a claw whose runtime has the scheduler enabled (`cron status`). openclaw only. |
100
102
  | `arkclaw profile save/use/list` | Named snapshots of the session config (multi-space / multi-claw). |
101
103
  | `arkclaw doctor` | Self-check: login freshness, keychain, pool/STS/endpoint reachability. |
102
104
  | `arkclaw schema --json` | Machine-readable command surface (for agents/tooling). |
103
- | `arkclaw claw list/describe/create/delete` | Fleet management on the control plane. |
104
105
 
105
106
  All commands accept `--clawid ci-...` (where relevant) to target a specific claw, and `--json` for machine output.
106
107
 
@@ -130,7 +131,7 @@ The CLI moves files across **three distinct planes** — pick by what you're car
130
131
  |---|---|---|
131
132
  | **Managed brain** | `ls` · `pull` · `push` | The claw's own config files (`AGENTS.md`, `SOUL.md`, …). A fixed allow-list, not a general store. |
132
133
  | **Workspace (Silk)** | `ls <path>` · `upload` · `download` · `mkdir` | The claw's *real* working filesystem — arbitrary files, uploads, agent outputs, subdirectories. |
133
- | **Netdisk (IDS)** | `netdisk …` | A separate large-object store for big products/videos, on a dedicated storage account. |
134
+ | **Netdisk (IDS)** | `netdisk …` | A separate large-object store for big products/videos; per-user creds minted from your SSO login. |
134
135
 
135
136
  ### 1. Managed brain files — `ls` / `pull` / `push`
136
137
 
@@ -170,26 +171,58 @@ arkclaw download runs ./runs.tar # a directory downloads as a .tar
170
171
 
171
172
  ### 3. Netdisk (IDS) — `netdisk …`
172
173
 
173
- A separate storage plane for large products/videos, on a **dedicated IDS
174
- account** (not your SSO identity). Configured entirely from `IDS_*` env vars
175
- (provisioned by the storage team). Create a space once, then pass its `SpaceID`:
174
+ A separate storage plane for large products/videos. Credentials are **minted
175
+ per-user from your SSO login** no static AK/SK: the claw's iDrive instance is
176
+ resolved and a minimal-permission temp credential is issued for *your*
177
+ `UserPoolUserUid` (`GetIDriveInstance` → `GetIDriveCredential`). `--space`
178
+ defaults to the claw's iDrive space; pass it to target another.
176
179
 
177
180
  ```bash
178
- arkclaw netdisk create-space my-space # prints the SpaceID
179
- arkclaw netdisk mkdir outputs --space spc-...
180
- arkclaw netdisk upload ./final.mp4 outputs/final.mp4 --space spc-...
181
- arkclaw netdisk ls outputs/ --space spc-...
182
- arkclaw netdisk download outputs/final.mp4 ./final.mp4 --space spc-...
183
- arkclaw netdisk rm outputs/final.mp4 --space spc-... # asks unless --yes
181
+ arkclaw netdisk ls # the claw's iDrive space
182
+ arkclaw netdisk upload ./final.mp4 outputs/final.mp4
183
+ arkclaw netdisk download outputs/final.mp4 ./final.mp4
184
+ arkclaw netdisk mkdir outputs
185
+ arkclaw netdisk rm outputs/final.mp4 # asks unless --yes
186
+ arkclaw netdisk create-space my-space # a second space prints its SpaceID
187
+ arkclaw netdisk ls --space spc-... # target a specific space
184
188
  ```
185
189
 
186
190
  `create-space` also takes `--description`; `ls` takes `--limit N` to cap entries.
187
191
 
192
+ For CI / a dedicated storage account you can still override the identity path:
193
+
188
194
  | Env | Purpose |
189
195
  |---|---|
190
- | `IDS_BASE_URL` / `IDS_REGION` / `IDS_SERVICE` / `IDS_INSTANCE_ID` | Endpoint + routing for the IDS instance. |
191
- | `IDS_AK` / `IDS_SK` (+ `IDS_ACCOUNT_ID`) | Static credentials for the storage account |
192
- | `IDS_ROLE_TRN` | …or assume a role via SSO instead of static AK/SK. |
196
+ | `IDS_ROLE_TRN` (+ `IDS_BASE_URL` / `IDS_REGION` / `IDS_SERVICE` / `IDS_INSTANCE_ID`) | Assume an IDS role via SSO instead. |
197
+ | `IDS_AK` / `IDS_SK` (+ `IDS_ACCOUNT_ID`, endpoint/routing vars) | Static credentials for a dedicated storage account. |
198
+
199
+ ---
200
+
201
+ ## Scheduled tasks — `cron`
202
+
203
+ Let a claw run a prompt **unattended** on a schedule (its runtime carries a
204
+ scheduler; check it with `arkclaw cron status`). A task is an *agent turn* — the
205
+ `--message` is the prompt the agent runs at each fire.
206
+
207
+ ```bash
208
+ arkclaw cron status # is the scheduler on; jobs; next wake
209
+ arkclaw cron add --name 早报 \
210
+ --cron "0 9 * * *" --tz Asia/Shanghai \
211
+ -m "联网搜集今天的科技新闻,生成一份中文摘要" # every day 09:00
212
+ arkclaw cron add --name 巡检 --every 30m -m "检查服务健康并报告异常"
213
+ arkclaw cron add --name 一次性 --at 2026-07-01T09:00:00+08:00 -m "提醒我项目截止" --delete-after-run
214
+ arkclaw cron list # all jobs (enabled + disabled)
215
+ arkclaw cron run <id> # fire one now (server-side)
216
+ arkclaw cron runs <id> # recent run history + status
217
+ arkclaw cron update <id> --disable # pause; --enable to resume
218
+ arkclaw cron rm <id> # delete (asks unless --yes)
219
+ ```
220
+
221
+ Schedule is exactly one of `--cron "<expr>"` (with optional `--tz`), `--every
222
+ <30s|15m|2h|1d>`, or `--at <ISO8601>`. `--session-target` picks where the run
223
+ lives (`isolated` default / `main` / `current`); `--agent` runs it as a specific
224
+ agent. Jobs the platform manages (created by an agent-pack template) are marked
225
+ `*` in the list — edit those in the console, not here. openclaw plane only.
193
226
 
194
227
  ---
195
228
 
@@ -213,8 +246,10 @@ arkclaw netdisk rm outputs/final.mp4 --space spc-... # asks unless --yes
213
246
  ## Configuration
214
247
 
215
248
  `login` resolves config in this order: **explicit flag → `ARKCLAW_*` env →
216
- the space's published discovery → `arkclaw init` defaults → derived from the
217
- address**. You normally only type the address.
249
+ the space's discovery → `arkclaw init` defaults → derived from the address**.
250
+ You normally only type the address — when the space exposes the CLI bootstrap
251
+ endpoint, `login` auto-fetches its public OAuth client + STS role, so even
252
+ `--client-id` / `--role-trn` are optional.
218
253
 
219
254
  **The easy way — `arkclaw init`** asks once (interactively) for whatever the
220
255
  space doesn't yet auto-publish, and saves it. After that, just `arkclaw login`.
@@ -228,6 +263,7 @@ values via env:
228
263
  | `ARKCLAW_ROLE_TRN` | STS role that mints the ChatToken (openclaw). |
229
264
  | `ARKCLAW_REGION` / `ARKCLAW_SPACE_ID` | Override region / space (usually auto). |
230
265
  | `ARKCLAW_API_HOST` / `ARKCLAW_API_SERVICE` | **Advanced/testing.** Point the control-plane calls at a non-production plane (host + SigV4 service). See the note below. |
266
+ | `ARKCLAW_FORWARD_ENV` | **Advanced/non-prod.** Adds an `X-Forward-Env` header to the space's CLI-bootstrap call to route to a small-traffic gateway. Unset (production) sends no header. |
231
267
 
232
268
  Other config: `~/.arkclaw/defaults.json` (`init` answers, 0600), `~/.arkclaw/session.json` (routing, 0600), `~/.arkclaw/cmdpolicy.json` (tool-approval allow/deny), OS keychain (tokens).
233
269
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arkclaw-webchat-cli"
7
- version = "0.9.0"
7
+ version = "0.13.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"
@@ -238,16 +238,27 @@ def history(
238
238
  show_tools: bool = typer.Option(
239
239
  False, "--show-tools", help="Also show tool calls/results (default: conversation only)."
240
240
  ),
241
+ tail: int = typer.Option(
242
+ flows.DEFAULT_HISTORY_TAIL,
243
+ "--tail",
244
+ "-n",
245
+ help=f"Show only the last N messages on screen (default {flows.DEFAULT_HISTORY_TAIL}).",
246
+ ),
247
+ all_messages: bool = typer.Option(
248
+ False, "--all", help="Show the whole transcript on screen (no tail cap)."
249
+ ),
241
250
  json_mode: bool = _json_opt(),
242
251
  ) -> None:
243
- """Read a past conversation's full transcript (ws `chat.history`). Get the
244
- 会话ID from `arkclaw sessions`, then `arkclaw history <会话ID>`. `--json`
245
- returns every message (incl. tool steps); `-o` writes a plain-text log."""
252
+ """Read a past conversation's transcript (ws `chat.history`). Get the 会话ID
253
+ from `arkclaw sessions`, then `arkclaw history <会话ID>`. The screen shows the
254
+ last `--tail` messages (default 50; `--all` for everything); `-o` and `--json`
255
+ always carry the full transcript (incl. tool steps for `--json`)."""
246
256
  emitter = Emitter(json_mode=json_mode)
247
257
  _run(
248
258
  emitter,
249
259
  lambda: flows.do_history(
250
- emitter, session, clawid=clawid, agent=agent, output=output, show_tools=show_tools
260
+ emitter, session, clawid=clawid, agent=agent, output=output,
261
+ show_tools=show_tools, tail=tail, show_all=all_messages,
251
262
  ),
252
263
  )
253
264
 
@@ -417,14 +428,200 @@ def fanout(
417
428
  )
418
429
 
419
430
 
420
- def _space_opt() -> str:
421
- return typer.Option(..., "--space", help="Netdisk SpaceID (from `netdisk create-space`).")
431
+ cron_app = typer.Typer(
432
+ no_args_is_help=True,
433
+ help="定时任务:让 claw 按计划(cron 表达式 / 固定间隔 / 指定时间)自动跑一段 agent 任务 "
434
+ "(无人值守)。需要运行时开了调度器的 claw —— `arkclaw cron status` 先确认。",
435
+ )
436
+ app.add_typer(cron_app, name="cron")
437
+
438
+
439
+ def _cron_clawid() -> str | None:
440
+ return typer.Option(
441
+ None, "--clawid", help="Claw instance id (ci-...). Omit to use your default claw."
442
+ )
443
+
444
+
445
+ @cron_app.command("status")
446
+ def cron_status(clawid: str | None = _cron_clawid(), json_mode: bool = _json_opt()) -> None:
447
+ """Is this claw's scheduler running, how many jobs, and when it next wakes."""
448
+ emitter = Emitter(json_mode=json_mode)
449
+ _run(emitter, lambda: flows.do_cron_status(emitter, clawid=clawid))
450
+
451
+
452
+ @cron_app.command("list")
453
+ def cron_list(clawid: str | None = _cron_clawid(), json_mode: bool = _json_opt()) -> None:
454
+ """List the claw's scheduled jobs (enabled and disabled). `cron get <id>`
455
+ for one job's full definition; `cron run <id>` to fire it now."""
456
+ emitter = Emitter(json_mode=json_mode)
457
+ _run(emitter, lambda: flows.do_cron_list(emitter, clawid=clawid))
458
+
459
+
460
+ @cron_app.command("get")
461
+ def cron_get(
462
+ job_id: str = typer.Argument(..., metavar="ID", help="Job id from `cron list`."),
463
+ clawid: str | None = _cron_clawid(),
464
+ json_mode: bool = _json_opt(),
465
+ ) -> None:
466
+ """Show one scheduled job's full definition + last-run state."""
467
+ emitter = Emitter(json_mode=json_mode)
468
+ _run(emitter, lambda: flows.do_cron_get(emitter, job_id, clawid=clawid))
469
+
470
+
471
+ @cron_app.command("add")
472
+ def cron_add(
473
+ name: str = typer.Option(..., "--name", help="任务名(显示用)。"),
474
+ message: str = typer.Option(
475
+ ..., "--message", "-m", help="到点让 agent 执行的提示词(无人值守的一段任务)。"
476
+ ),
477
+ cron_expr: str | None = typer.Option(
478
+ None, "--cron", help='Cron 表达式,如 "0 9 * * *"(每天9点)。与 --every/--at 三选一。'
479
+ ),
480
+ every: str | None = typer.Option(
481
+ None, "--every", help="固定间隔:30s / 15m / 2h / 1d。与 --cron/--at 三选一。"
482
+ ),
483
+ at: str | None = typer.Option(
484
+ None, "--at", help="只跑一次的时间点(ISO8601),如 2026-07-01T09:00:00+08:00。"
485
+ ),
486
+ tz: str | None = typer.Option(
487
+ None, "--tz", help='时区(配合 --cron),如 Asia/Shanghai。'
488
+ ),
489
+ agent: str | None = typer.Option(
490
+ None, "--agent", help="用哪个 agent 执行(agentId;默认 claw 的主 agent)。"
491
+ ),
492
+ model: str | None = typer.Option(None, "--model", help="覆盖执行用的模型(可选)。"),
493
+ timeout: int | None = typer.Option(
494
+ None, "--timeout", help="单次运行的超时(秒,可选)。"
495
+ ),
496
+ session_target: str = typer.Option(
497
+ "isolated",
498
+ "--session-target",
499
+ help="会话目标:isolated(每次独立,默认)/ main(主会话)/ current。",
500
+ ),
501
+ disabled: bool = typer.Option(
502
+ False, "--disabled", help="创建后先不启用(默认启用)。"
503
+ ),
504
+ delete_after_run: bool = typer.Option(
505
+ False, "--delete-after-run", help="跑完一次就删除(常配合 --at)。"
506
+ ),
507
+ clawid: str | None = _cron_clawid(),
508
+ json_mode: bool = _json_opt(),
509
+ ) -> None:
510
+ """Create a scheduled agent-turn task. Give a schedule (exactly one of
511
+ --cron / --every / --at) and the --message the agent runs unattended.
512
+ Example: `arkclaw cron add --name 早报 --cron "0 9 * * *" -m "生成今日新闻摘要"`."""
513
+ emitter = Emitter(json_mode=json_mode)
514
+ _run(
515
+ emitter,
516
+ lambda: flows.do_cron_add(
517
+ emitter,
518
+ name=name,
519
+ message=message,
520
+ cron_expr=cron_expr,
521
+ every=every,
522
+ at=at,
523
+ tz=tz,
524
+ agent=agent,
525
+ model=model,
526
+ timeout=timeout,
527
+ session_target=session_target,
528
+ enabled=not disabled,
529
+ delete_after_run=delete_after_run,
530
+ clawid=clawid,
531
+ ),
532
+ )
533
+
534
+
535
+ @cron_app.command("update")
536
+ def cron_update(
537
+ job_id: str = typer.Argument(..., metavar="ID", help="Job id from `cron list`."),
538
+ name: str | None = typer.Option(None, "--name", help="新任务名。"),
539
+ message: str | None = typer.Option(None, "--message", "-m", help="新的任务提示词。"),
540
+ cron_expr: str | None = typer.Option(None, "--cron", help='新 cron 表达式。'),
541
+ every: str | None = typer.Option(None, "--every", help="新间隔:30s/15m/2h/1d。"),
542
+ at: str | None = typer.Option(None, "--at", help="新的一次性时间点(ISO8601)。"),
543
+ tz: str | None = typer.Option(None, "--tz", help="时区(配合 --cron)。"),
544
+ enable: bool = typer.Option(False, "--enable", help="启用该任务。"),
545
+ disable: bool = typer.Option(False, "--disable", help="停用该任务。"),
546
+ clawid: str | None = _cron_clawid(),
547
+ json_mode: bool = _json_opt(),
548
+ ) -> None:
549
+ """Patch a job — only the fields you pass change (name / schedule / message /
550
+ enabled)."""
551
+ emitter = Emitter(json_mode=json_mode)
552
+ if enable and disable:
553
+ raise typer.Exit(
554
+ emitter.fail(ValidationError("--enable 和 --disable 不能同时给。"))
555
+ )
556
+ enable_val: bool | None = True if enable else (False if disable else None)
557
+ _run(
558
+ emitter,
559
+ lambda: flows.do_cron_update(
560
+ emitter,
561
+ job_id,
562
+ name=name,
563
+ message=message,
564
+ cron_expr=cron_expr,
565
+ every=every,
566
+ at=at,
567
+ tz=tz,
568
+ enable=enable_val,
569
+ clawid=clawid,
570
+ ),
571
+ )
572
+
573
+
574
+ @cron_app.command("rm")
575
+ def cron_rm(
576
+ job_id: str = typer.Argument(..., metavar="ID", help="Job id from `cron list`."),
577
+ yes: bool = typer.Option(False, "--yes", help="Skip the confirmation prompt."),
578
+ clawid: str | None = _cron_clawid(),
579
+ json_mode: bool = _json_opt(),
580
+ ) -> None:
581
+ """Delete a scheduled job (asks for confirmation unless --yes)."""
582
+ emitter = Emitter(json_mode=json_mode)
583
+ _run(emitter, lambda: flows.do_cron_remove(emitter, job_id, clawid=clawid, yes=yes))
584
+
585
+
586
+ @cron_app.command("run")
587
+ def cron_run(
588
+ job_id: str = typer.Argument(..., metavar="ID", help="Job id from `cron list`."),
589
+ due: bool = typer.Option(
590
+ False, "--due", help="只在当前确实到点时才跑(默认强制立即跑)。"
591
+ ),
592
+ clawid: str | None = _cron_clawid(),
593
+ json_mode: bool = _json_opt(),
594
+ ) -> None:
595
+ """Fire a scheduled job now (runs server-side; `cron runs <id>` for results)."""
596
+ emitter = Emitter(json_mode=json_mode)
597
+ _run(emitter, lambda: flows.do_cron_run(emitter, job_id, clawid=clawid, due_only=due))
598
+
599
+
600
+ @cron_app.command("runs")
601
+ def cron_runs(
602
+ job_id: str | None = typer.Argument(
603
+ None, metavar="[ID]", help="Job id; omit for the whole claw's history."
604
+ ),
605
+ limit: int = typer.Option(10, "--limit", "-n", help="Max entries to show."),
606
+ clawid: str | None = _cron_clawid(),
607
+ json_mode: bool = _json_opt(),
608
+ ) -> None:
609
+ """Recent run history — one job (with ID) or the whole claw (without)."""
610
+ emitter = Emitter(json_mode=json_mode)
611
+ _run(emitter, lambda: flows.do_cron_runs(emitter, job_id, clawid=clawid, limit=limit))
612
+
613
+
614
+ def _space_opt() -> str | None:
615
+ return typer.Option(
616
+ None, "--space",
617
+ help="Netdisk SpaceID. Defaults to the claw's iDrive space; set to target another.",
618
+ )
422
619
 
423
620
 
424
621
  netdisk_app = typer.Typer(
425
622
  no_args_is_help=True,
426
- help="IDS 网盘 (large products / videos): a separate storage plane. Configure "
427
- "via IDS_* env vars (base_url/account/ak/sk/region/service/instance, from the storage team).",
623
+ help="IDS 网盘 (large products / videos): a separate storage plane. Credentials are "
624
+ "minted per-user from your SSO login (no static AK/SK). IDS_* env still override for CI.",
428
625
  )
429
626
  app.add_typer(netdisk_app, name="netdisk")
430
627
 
@@ -443,7 +640,7 @@ def netdisk_create_space(
443
640
  @netdisk_app.command("ls")
444
641
  def netdisk_ls(
445
642
  prefix: str = typer.Argument("", help="Dir prefix to list (e.g. 'outputs/'). Omit for root."),
446
- space: str = _space_opt(),
643
+ space: str | None = _space_opt(),
447
644
  limit: int | None = typer.Option(None, "--limit", help="Max entries to return."),
448
645
  json_mode: bool = _json_opt(),
449
646
  ) -> None:
@@ -456,7 +653,7 @@ def netdisk_ls(
456
653
  def netdisk_upload(
457
654
  local: str = typer.Argument(..., help="Local file to upload."),
458
655
  remote: str | None = typer.Argument(None, help="Netdisk path (default: basename)."),
459
- space: str = _space_opt(),
656
+ space: str | None = _space_opt(),
460
657
  json_mode: bool = _json_opt(),
461
658
  ) -> None:
462
659
  """Upload a file into a netdisk space."""
@@ -468,7 +665,7 @@ def netdisk_upload(
468
665
  def netdisk_download(
469
666
  remote: str = typer.Argument(..., help="Netdisk file path to download."),
470
667
  local: str | None = typer.Argument(None, help="Local path (default: same name here)."),
471
- space: str = _space_opt(),
668
+ space: str | None = _space_opt(),
472
669
  json_mode: bool = _json_opt(),
473
670
  ) -> None:
474
671
  """Download a netdisk file (streamed to disk)."""
@@ -479,7 +676,7 @@ def netdisk_download(
479
676
  @netdisk_app.command("mkdir")
480
677
  def netdisk_mkdir(
481
678
  path: str = typer.Argument(..., help="Netdisk folder path to create."),
482
- space: str = _space_opt(),
679
+ space: str | None = _space_opt(),
483
680
  json_mode: bool = _json_opt(),
484
681
  ) -> None:
485
682
  """Create a folder in a netdisk space."""
@@ -490,7 +687,7 @@ def netdisk_mkdir(
490
687
  @netdisk_app.command("rm")
491
688
  def netdisk_rm(
492
689
  remote: str = typer.Argument(..., help="Netdisk file path to delete."),
493
- space: str = _space_opt(),
690
+ space: str | None = _space_opt(),
494
691
  yes: bool = typer.Option(False, "--yes", help="Skip the confirmation prompt."),
495
692
  json_mode: bool = _json_opt(),
496
693
  ) -> None:
@@ -499,53 +696,6 @@ def netdisk_rm(
499
696
  _run(emitter, lambda: flows.do_netdisk_rm(emitter, space, remote, yes=yes))
500
697
 
501
698
 
502
- claw_app = typer.Typer(
503
- no_args_is_help=True,
504
- help="Fleet: manage claw instances on the control plane.",
505
- )
506
- app.add_typer(claw_app, name="claw")
507
-
508
-
509
- @claw_app.command("list")
510
- def claw_list(json_mode: bool = _json_opt()) -> None:
511
- """List claw instances in the logged-in space's project."""
512
- emitter = Emitter(json_mode=json_mode)
513
- _run(emitter, lambda: flows.do_claw(emitter, "list"))
514
-
515
-
516
- @claw_app.command("describe")
517
- def claw_describe(
518
- clawid: str = typer.Argument(..., help="Claw instance id (ci-...)."),
519
- json_mode: bool = _json_opt(),
520
- ) -> None:
521
- """Describe one claw instance."""
522
- emitter = Emitter(json_mode=json_mode)
523
- _run(emitter, lambda: flows.do_claw(emitter, "describe", clawid=clawid))
524
-
525
-
526
- @claw_app.command("create")
527
- def claw_create(
528
- body: str = typer.Option(
529
- ..., "--body", help='Raw create request JSON, e.g. \'{"Name": "my-claw"}\'.'
530
- ),
531
- json_mode: bool = _json_opt(),
532
- ) -> None:
533
- """Create a claw instance (raw control-plane body passthrough)."""
534
- emitter = Emitter(json_mode=json_mode)
535
- _run(emitter, lambda: flows.do_claw(emitter, "create", body=body))
536
-
537
-
538
- @claw_app.command("delete")
539
- def claw_delete(
540
- clawid: str = typer.Argument(..., help="Claw instance id (ci-...)."),
541
- yes: bool = typer.Option(False, "--yes", help="Skip the confirmation prompt."),
542
- json_mode: bool = _json_opt(),
543
- ) -> None:
544
- """Delete a claw instance (asks for confirmation unless --yes)."""
545
- emitter = Emitter(json_mode=json_mode)
546
- _run(emitter, lambda: flows.do_claw(emitter, "delete", clawid=clawid, yes=yes))
547
-
548
-
549
699
  @app.command()
550
700
  def doctor(json_mode: bool = _json_opt()) -> None:
551
701
  """Self-check: config, login freshness, keychain, pool/STS/endpoint