Skip to content

Commit 51ff321

Browse files
Feat: support new apis (#3)
* feat: 新增GetClawSpace sdk和cli * feat: 新增ListUsersModelConfig sdk和cli - spec 中注册 ListUsersModelConfig(GET,必填 SpaceId,可选 MaxResults/NextToken/UserIds.N) - SpaceOperations 新增 list_users_model_config 方法 - CLI 新增 `space list-users-model-config` 子命令 * feat: 新增ListUsers sdk和cli,并同步README/CHANGELOG - spec 中注册 ListUsers(GET,必填 SpaceId,支持 Filter.* 与分页参数) - UserOperations 新增 list 方法,接受 filter dict / max_results / next_token - CLI 新增 `user list` 子命令,覆盖所有 Filter 字段 - 修复 spec 中 `.N` 列表标记的字面剥离(例如 `Filter.Name` -> `Filterame`),改为位置正则匹配 - README/CHANGELOG 补齐 GetClawSpace、ListUsersModelConfig、ListUsers 相关文档 * feat: 更新CreateClawInstance/UpdateClawInstance/CreateUsers与最新OpenAPI对齐 * chore: prepare for pypi release * feat: 更新CreateClawInstance/UpdateClawInstance/CreateUsers与最新OpenAPI对齐
1 parent 24ca783 commit 51ff321

9 files changed

Lines changed: 366 additions & 28 deletions

File tree

CHANGELOG.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,38 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [Unreleased]
6+
7+
### Added
8+
9+
- `GetClawSpace`: `client.spaces.get` and `arkclaw space get` for retrieving
10+
ArkClaw space detail (endpoints, auth type, status, APM ID).
11+
- `ListUsersModelConfig`: `client.spaces.list_users_model_config` and
12+
`arkclaw space list-users-model-config` for paginated user model
13+
configuration lookup with optional `UserIds` filter.
14+
- `ListUsers`: `client.users.list` and `arkclaw user list` for listing users
15+
in a space with department, group, email, phone, name, and user-ID filters.
16+
- `CreateClawInstance`: new optional parameters `EnableHeadless`,
17+
`ClientToken`, `DryRun` on `client.instances.create` and
18+
`arkclaw instance create`.
19+
- `UpdateClawInstance`: reassign or unbind the owning user via
20+
`client.instances.update(user_id=...)` / `arkclaw instance update --user-id`,
21+
which populates `Patch.UserId.Value` and `FieldMask.Paths=[Patch.UserId]`
22+
under the hood. Omitting `user_id` leaves the binding untouched; passing an
23+
empty string or `None` unbinds the current user.
24+
25+
### Changed
26+
27+
- `CreateClawInstance`: `UserId` is now optional (was required).
28+
- `CreateUsers`: spec explicitly declares `Users` as a required `object[]`;
29+
user element fields remain the same.
30+
31+
### Fixed
32+
33+
- Parameter spec `.N` list-marker stripping now uses a positional regex so
34+
legitimate field names such as `Filter.Name` are no longer mangled into
35+
`Filterame`.
36+
537
## [0.1.0] - 2026-06-23
638

739
### Added

README.md

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ Spaces:
5252
| OpenAPI action | SDK method | CLI command |
5353
|---|---|---|
5454
| `ListClawSpaces` | `client.spaces.list` | `arkclaw space list` |
55+
| `GetClawSpace` | `client.spaces.get` | `arkclaw space get` |
5556
| `UpdateUsersModelConfig` | `client.spaces.update_users_model_config` | `arkclaw space update-users-model-config` |
57+
| `ListUsersModelConfig` | `client.spaces.list_users_model_config` | `arkclaw space list-users-model-config` |
5658

5759
Instances:
5860

@@ -79,6 +81,7 @@ Users:
7981
| `CreateUser` | `client.users.create` | `arkclaw user create` |
8082
| `UpdateUser` | `client.users.update` | `arkclaw user update` |
8183
| `DeleteUser` | `client.users.delete` | `arkclaw user delete` |
84+
| `ListUsers` | `client.users.list` | `arkclaw user list` |
8285

8386
Additional SDK workflows include `wait_for_instance`, `provision_instance`, and
8487
`prepare_chat_access` under `client.workflows`.
@@ -92,6 +95,20 @@ client = ArkClawClient.from_env()
9295

9396
spaces = client.spaces.list()
9497

98+
space = client.spaces.get(space_id="csi-xxx")
99+
100+
user_configs = client.spaces.list_users_model_config(
101+
space_id="csi-xxx",
102+
user_ids=["user-xxx"],
103+
max_results=20,
104+
)
105+
106+
users_page = client.users.list(
107+
space_id="csi-xxx",
108+
filter={"name": "zhang", "user_ids": ["user-xxx"]},
109+
max_results=20,
110+
)
111+
95112
model_config_result = client.spaces.update_users_model_config(
96113
space_id="csi-xxx",
97114
user_ids=["user-xxx"],
@@ -128,6 +145,12 @@ client.instances.update(
128145
instance_name="demo-claw-renamed",
129146
)
130147

148+
client.instances.update(
149+
space_id="csi-xxx",
150+
instance_id=instance["InstanceId"],
151+
user_id="user-yyy", # pass "" to unbind the current owner
152+
)
153+
131154
terminal = client.instances.get_terminal_token(
132155
space_id="csi-xxx",
133156
instance_id=instance["InstanceId"],
@@ -221,8 +244,8 @@ Supported command groups and subcommands:
221244

222245
| Group | Subcommands |
223246
|---|---|
224-
| `space` | `list`, `update-users-model-config` |
225-
| `user` | `create`, `create-many`, `update`, `delete` |
247+
| `space` | `list`, `get`, `update-users-model-config`, `list-users-model-config` |
248+
| `user` | `create`, `create-many`, `update`, `delete`, `list` |
226249
| `instance` | `create`, `update-model`, `chat-token`, `get`, `update-channel`, `list`, `start`, `stop`, `reset`, `update`, `delete`, `terminal-token`, `wait` |
227250
| `message` | `send`, `shell` |
228251

@@ -231,11 +254,24 @@ Selected examples:
231254
```bash
232255
arkclaw space list
233256

257+
arkclaw space get --space-id csi-xxx
258+
259+
arkclaw space list-users-model-config \
260+
--space-id csi-xxx \
261+
--user-id user-xxx \
262+
--max-results 20
263+
234264
arkclaw space update-users-model-config \
235265
--space-id csi-xxx \
236266
--user-id user-xxx \
237267
--coding-plan-seat-type Lite
238268

269+
arkclaw user list \
270+
--space-id csi-xxx \
271+
--filter-name zhang \
272+
--filter-user-id user-xxx \
273+
--max-results 20
274+
239275
arkclaw user create \
240276
--space-id csi-xxx \
241277
--email alice@example.com \
@@ -266,6 +302,11 @@ arkclaw instance update \
266302
--instance-id ci-xxx \
267303
--instance-name demo-claw-renamed
268304

305+
arkclaw instance update \
306+
--space-id csi-xxx \
307+
--instance-id ci-xxx \
308+
--user-id user-yyy # pass "" to unbind the current owner
309+
269310
arkclaw instance terminal-token \
270311
--space-id csi-xxx \
271312
--instance-id ci-xxx

arkclaw/cli/instances.py

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,25 @@
2121
from ._common import build_client, emit, info
2222

2323

24+
_CLI_USER_ID_UNSET = object()
25+
26+
2427
def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[type-arg]
2528
group = subparsers.add_parser("instance", help="ClawInstance management")
2629
sub = group.add_subparsers(dest="instance_action")
2730
sub.required = True
2831

2932
p = sub.add_parser("create", help="Create a ClawInstance")
3033
p.add_argument("--space-id", required=True)
31-
p.add_argument("--user-id", required=True)
34+
p.add_argument("--user-id", default=None)
3235
p.add_argument("--instance-name", required=True)
3336
p.add_argument("--seat-type", required=True, choices=["Starter", "Standard", "Premium", "Ultimate"])
3437
p.add_argument("--description", default=None)
3538
p.add_argument("--model-api-key", default=None)
3639
p.add_argument("--template-id", default=None)
40+
p.add_argument("--enable-headless", choices=["true", "false"], default=None)
41+
p.add_argument("--client-token", default=None)
42+
p.add_argument("--dry-run", choices=["true", "false"], default=None)
3743
p.add_argument("--wait", action="store_true", default=False)
3844
p.add_argument("--wait-timeout", type=float, default=600)
3945
p.add_argument("--interval", type=float, default=5)
@@ -101,6 +107,11 @@ def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[ty
101107
p.add_argument("--space-id", required=True)
102108
p.add_argument("--instance-id", required=True)
103109
p.add_argument("--instance-name", default=None)
110+
p.add_argument(
111+
"--user-id",
112+
default=_CLI_USER_ID_UNSET,
113+
help="Reassign the instance to this user ID; pass an empty string to unbind. Omit to leave the binding unchanged.",
114+
)
104115
p.add_argument("--client-token", default=None)
105116
p.add_argument("--dry-run", choices=["true", "false"], default=None)
106117
p.set_defaults(func=_update)
@@ -129,6 +140,8 @@ def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[ty
129140

130141
def _create(args: argparse.Namespace) -> None:
131142
client = build_client(args)
143+
enable_headless = None if args.enable_headless is None else args.enable_headless == "true"
144+
dry_run = None if args.dry_run is None else args.dry_run == "true"
132145
if args.wait:
133146
info(f"Creating {args.instance_name} and waiting for Running...")
134147
result = client.workflows.provision_instance(
@@ -151,6 +164,9 @@ def _create(args: argparse.Namespace) -> None:
151164
description=args.description,
152165
model_api_key=args.model_api_key,
153166
template_id=args.template_id,
167+
enable_headless=enable_headless,
168+
client_token=args.client_token,
169+
dry_run=dry_run,
154170
)
155171
emit(result)
156172

@@ -258,15 +274,16 @@ def _reset(args: argparse.Namespace) -> None:
258274
def _update(args: argparse.Namespace) -> None:
259275
client = build_client(args)
260276
dry_run = None if args.dry_run is None else args.dry_run == "true"
261-
emit(
262-
client.instances.update(
263-
space_id=args.space_id,
264-
instance_id=args.instance_id,
265-
instance_name=None if args.instance_name in (None, "") else args.instance_name,
266-
client_token=args.client_token,
267-
dry_run=dry_run,
268-
)
277+
update_kwargs: dict[str, Any] = dict(
278+
space_id=args.space_id,
279+
instance_id=args.instance_id,
280+
instance_name=None if args.instance_name in (None, "") else args.instance_name,
281+
client_token=args.client_token,
282+
dry_run=dry_run,
269283
)
284+
if args.user_id is not _CLI_USER_ID_UNSET:
285+
update_kwargs["user_id"] = args.user_id
286+
emit(client.instances.update(**update_kwargs))
270287

271288

272289
def _delete(args: argparse.Namespace) -> None:

arkclaw/cli/spaces.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[ty
3030
p.add_argument("--space-name", default=None)
3131
p.set_defaults(func=_list)
3232

33+
p = sub.add_parser("get", help="Get ClawSpace detail")
34+
p.add_argument("--space-id", required=True)
35+
p.set_defaults(func=_get)
36+
3337
p = sub.add_parser("update-users-model-config", help="Update codingPlan seat type and token limits for users")
3438
p.add_argument("--space-id", required=True)
3539
p.add_argument("--user-id", dest="user_ids", action="append", required=True)
@@ -38,6 +42,13 @@ def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[ty
3842
p.add_argument("--token-rate-limit-per-day", type=int, default=None)
3943
p.set_defaults(func=_update_users_model_config)
4044

45+
p = sub.add_parser("list-users-model-config", help="List user model configurations in a space")
46+
p.add_argument("--space-id", required=True)
47+
p.add_argument("--user-id", dest="user_ids", action="append", default=None)
48+
p.add_argument("--max-results", type=int, default=None)
49+
p.add_argument("--next-token", default=None)
50+
p.set_defaults(func=_list_users_model_config)
51+
4152

4253
def _model_config_kwargs(args: argparse.Namespace) -> dict[str, Any]:
4354
return {
@@ -52,6 +63,11 @@ def _list(args: argparse.Namespace) -> None:
5263
emit(client.spaces.list(project_name=args.project_name, space_name=args.space_name))
5364

5465

66+
def _get(args: argparse.Namespace) -> None:
67+
client = build_client(args)
68+
emit(client.spaces.get(space_id=args.space_id))
69+
70+
5571
def _update_users_model_config(args: argparse.Namespace) -> None:
5672
client = build_client(args)
5773
emit(
@@ -61,3 +77,15 @@ def _update_users_model_config(args: argparse.Namespace) -> None:
6177
model_config=_model_config_kwargs(args),
6278
)
6379
)
80+
81+
82+
def _list_users_model_config(args: argparse.Namespace) -> None:
83+
client = build_client(args)
84+
emit(
85+
client.spaces.list_users_model_config(
86+
space_id=args.space_id,
87+
user_ids=args.user_ids,
88+
max_results=args.max_results,
89+
next_token=args.next_token,
90+
)
91+
)

arkclaw/cli/users.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,48 @@ def register(subparsers: argparse._SubParsersAction) -> None: # type: ignore[ty
4747
p.add_argument("--user-id", required=True)
4848
p.set_defaults(func=_delete)
4949

50+
p = sub.add_parser("list", help="List users in a space with optional filters")
51+
p.add_argument("--space-id", required=True)
52+
p.add_argument("--max-results", type=int, default=None)
53+
p.add_argument("--next-token", default=None)
54+
p.add_argument("--filter-department-uid", default=None)
55+
p.add_argument(
56+
"--filter-department-uid-recursive",
57+
dest="filter_department_uid_recursive",
58+
action="store_true",
59+
default=None,
60+
)
61+
p.add_argument("--filter-email", default=None)
62+
p.add_argument(
63+
"--filter-email-phone-name-is-null-or-empty",
64+
dest="filter_email_phone_name_is_null_or_empty",
65+
action="store_true",
66+
default=None,
67+
)
68+
p.add_argument("--filter-group-uid", default=None)
69+
p.add_argument("--filter-name", default=None)
70+
p.add_argument(
71+
"--filter-not-in-any-department",
72+
dest="filter_not_in_any_department",
73+
action="store_true",
74+
default=None,
75+
)
76+
p.add_argument(
77+
"--filter-not-in-any-group",
78+
dest="filter_not_in_any_group",
79+
action="store_true",
80+
default=None,
81+
)
82+
p.add_argument("--filter-phone-number", default=None)
83+
p.add_argument(
84+
"--filter-user-id",
85+
dest="filter_user_ids",
86+
action="append",
87+
default=None,
88+
help="User ID filter; may be given multiple times",
89+
)
90+
p.set_defaults(func=_list)
91+
5092

5193
def _add_user_fields(parser: argparse.ArgumentParser) -> None:
5294
parser.add_argument("--email", default=None)
@@ -90,3 +132,28 @@ def _delete(args: argparse.Namespace) -> None:
90132
client = build_client(args)
91133
emit(client.users.delete(space_id=args.space_id, user_id=args.user_id))
92134

135+
136+
def _list(args: argparse.Namespace) -> None:
137+
client = build_client(args)
138+
filter_kwargs: dict[str, Any] = {
139+
"department_uid": args.filter_department_uid,
140+
"department_uid_recursive": args.filter_department_uid_recursive,
141+
"email": args.filter_email,
142+
"email_phone_name_is_null_or_empty": args.filter_email_phone_name_is_null_or_empty,
143+
"group_uid": args.filter_group_uid,
144+
"name": args.filter_name,
145+
"not_in_any_department": args.filter_not_in_any_department,
146+
"not_in_any_group": args.filter_not_in_any_group,
147+
"phone_number": args.filter_phone_number,
148+
"user_ids": args.filter_user_ids,
149+
}
150+
filter_payload = {k: v for k, v in filter_kwargs.items() if v is not None}
151+
emit(
152+
client.users.list(
153+
space_id=args.space_id,
154+
filter=filter_payload or None,
155+
max_results=args.max_results,
156+
next_token=args.next_token,
157+
)
158+
)
159+

0 commit comments

Comments
 (0)