logion-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cli/__init__.py +2 -0
- cli/_config.py +51 -0
- cli/_confirm.py +16 -0
- cli/_context.py +17 -0
- cli/_course_bundle.py +46 -0
- cli/_course_capabilities.py +580 -0
- cli/_credentials.py +104 -0
- cli/_errors.py +82 -0
- cli/_first_run.py +90 -0
- cli/_harness/__init__.py +68 -0
- cli/_harness/base.py +106 -0
- cli/_harness/claude_code.py +168 -0
- cli/_harness/codex.py +79 -0
- cli/_harness/custom.py +55 -0
- cli/_harness/hermes.py +93 -0
- cli/_harness/opencode.py +255 -0
- cli/_local_state.py +1053 -0
- cli/_options.py +36 -0
- cli/_output.py +47 -0
- cli/_parser.py +73 -0
- cli/_recall_calibration.py +90 -0
- cli/_recall_ranker.py +74 -0
- cli/_taxonomy.py +120 -0
- cli/_update_policy.py +152 -0
- cli/_utils.py +16 -0
- cli/_version.py +26 -0
- cli/commands/__init__.py +2 -0
- cli/commands/admin.py +535 -0
- cli/commands/bounties.py +490 -0
- cli/commands/course_reviews/__init__.py +6 -0
- cli/commands/course_reviews/_download_handler.py +104 -0
- cli/commands/course_reviews/_render.py +129 -0
- cli/commands/course_reviews/handlers.py +197 -0
- cli/commands/course_reviews/parser.py +93 -0
- cli/commands/courses/__init__.py +6 -0
- cli/commands/courses/_capability_render.py +183 -0
- cli/commands/courses/_cmd_help.py +18 -0
- cli/commands/courses/_purchase.py +76 -0
- cli/commands/courses/_review_helpers.py +93 -0
- cli/commands/courses/_taxonomy_data.py +173 -0
- cli/commands/courses/_upload_bundle_validation.py +28 -0
- cli/commands/courses/_uploads_push.py +243 -0
- cli/commands/courses/capabilities.py +250 -0
- cli/commands/courses/capability_frontmatter.py +150 -0
- cli/commands/courses/handlers.py +50 -0
- cli/commands/courses/mutations.py +217 -0
- cli/commands/courses/parser.py +66 -0
- cli/commands/courses/parser_capabilities.py +95 -0
- cli/commands/courses/parser_sections.py +239 -0
- cli/commands/courses/parser_uploads.py +84 -0
- cli/commands/courses/parser_utils.py +65 -0
- cli/commands/courses/publication.py +60 -0
- cli/commands/courses/report_usage.py +131 -0
- cli/commands/courses/reviews.py +237 -0
- cli/commands/courses/taxonomy_handler.py +61 -0
- cli/commands/courses/taxonomy_suggest.py +197 -0
- cli/commands/courses/uploads.py +142 -0
- cli/commands/courses/versions.py +65 -0
- cli/commands/credits/__init__.py +6 -0
- cli/commands/credits/_helpers.py +153 -0
- cli/commands/credits/handlers.py +218 -0
- cli/commands/credits/parser.py +115 -0
- cli/commands/docs/__init__.py +6 -0
- cli/commands/docs/handlers.py +137 -0
- cli/commands/docs/parser.py +27 -0
- cli/commands/health/__init__.py +6 -0
- cli/commands/health/handlers.py +26 -0
- cli/commands/health/parser.py +20 -0
- cli/commands/identity/__init__.py +6 -0
- cli/commands/identity/_autopost.py +97 -0
- cli/commands/identity/_closing_copy.py +89 -0
- cli/commands/identity/_companion.py +232 -0
- cli/commands/identity/_companion_source.py +135 -0
- cli/commands/identity/_harness_select.py +85 -0
- cli/commands/identity/_onboarding_helpers.py +168 -0
- cli/commands/identity/handlers.py +173 -0
- cli/commands/identity/onboarding.py +246 -0
- cli/commands/identity/parser.py +72 -0
- cli/commands/listings/__init__.py +6 -0
- cli/commands/listings/handlers.py +135 -0
- cli/commands/listings/parser.py +57 -0
- cli/commands/notifications/__init__.py +6 -0
- cli/commands/notifications/handlers.py +120 -0
- cli/commands/notifications/parser.py +49 -0
- cli/commands/payments/__init__.py +6 -0
- cli/commands/payments/_orders_helpers.py +114 -0
- cli/commands/payments/handlers.py +138 -0
- cli/commands/payments/parser.py +97 -0
- cli/commands/recall/__init__.py +7 -0
- cli/commands/recall/handlers.py +87 -0
- cli/commands/recall/parser.py +70 -0
- cli/commands/referrals/__init__.py +6 -0
- cli/commands/referrals/_helpers.py +63 -0
- cli/commands/referrals/handlers.py +100 -0
- cli/commands/referrals/parser.py +65 -0
- cli/commands/reports/__init__.py +6 -0
- cli/commands/reports/handlers.py +57 -0
- cli/commands/reports/parser.py +52 -0
- cli/commands/skills/__init__.py +7 -0
- cli/commands/skills/_agent_symlink.py +161 -0
- cli/commands/skills/_finalize.py +112 -0
- cli/commands/skills/_inspect_handler.py +218 -0
- cli/commands/skills/_install_helpers.py +186 -0
- cli/commands/skills/_query_handlers.py +83 -0
- cli/commands/skills/_search_handler.py +136 -0
- cli/commands/skills/_update_handler.py +110 -0
- cli/commands/skills/_verify_handler.py +109 -0
- cli/commands/skills/handlers.py +202 -0
- cli/commands/skills/parser.py +154 -0
- cli/commands/workspace.py +406 -0
- cli/docs/README.md +5 -0
- cli/docs/__init__.py +1 -0
- cli/docs/bounties-and-referrals.md +18 -0
- cli/docs/concepts.md +47 -0
- cli/docs/creating-courses.md +25 -0
- cli/docs/credits-and-purchases.md +30 -0
- cli/docs/credits-terms.md +23 -0
- cli/docs/getting-started.md +95 -0
- cli/docs/marketplace-loop.md +108 -0
- cli/docs/privacy.md +30 -0
- cli/docs/referral-terms.md +24 -0
- cli/docs/reviews.md +47 -0
- cli/docs/safety.md +28 -0
- cli/docs/terms.md +54 -0
- cli/main.py +84 -0
- cli/templates/__init__.py +2 -0
- cli/templates/course_capabilities.template.yaml +189 -0
- cli/templates/course_license_apache-2.0.template.txt +30 -0
- cli/templates/course_license_logion-standard-course-v1.template.txt +49 -0
- cli/templates/course_license_mit.template.txt +21 -0
- logion_cli-0.1.0.dist-info/METADATA +49 -0
- logion_cli-0.1.0.dist-info/RECORD +135 -0
- logion_cli-0.1.0.dist-info/WHEEL +4 -0
- logion_cli-0.1.0.dist-info/entry_points.txt +4 -0
- logion_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
cli/commands/admin.py
ADDED
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Admin commands — courses/users/agents/reports administration.
|
|
3
|
+
|
|
4
|
+
Gated by ``LOGION_ENABLE_ADMIN``. If the env var is not truthy the
|
|
5
|
+
``admin`` subcommand is hidden: the parser prints *No such command* to
|
|
6
|
+
stderr and exits with code 2.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
|
|
13
|
+
from cli._config import is_admin_enabled, resolve_config_from_args
|
|
14
|
+
from cli._confirm import require_yes
|
|
15
|
+
from cli._context import make_client
|
|
16
|
+
from cli._errors import handle_error, print_err, validate_uuid_id
|
|
17
|
+
from cli._options import COMMON_PARSER
|
|
18
|
+
from cli._output import emit
|
|
19
|
+
from cli._utils import only_not_none
|
|
20
|
+
|
|
21
|
+
# ── Registration ──────────────────────────────────────────────────
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def register(subparsers: argparse._SubParsersAction) -> None:
|
|
25
|
+
"""Register the ``admin`` subcommand group.
|
|
26
|
+
|
|
27
|
+
If ``LOGION_ENABLE_ADMIN`` is not truthy, adds a stub parser that
|
|
28
|
+
exits with code 2 and prints *No such command* to stderr.
|
|
29
|
+
"""
|
|
30
|
+
if not is_admin_enabled():
|
|
31
|
+
parser = subparsers.add_parser(
|
|
32
|
+
"admin",
|
|
33
|
+
help=argparse.SUPPRESS,
|
|
34
|
+
add_help=False,
|
|
35
|
+
)
|
|
36
|
+
parser.set_defaults(handler=_handle_disabled)
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
parser = subparsers.add_parser(
|
|
40
|
+
"admin",
|
|
41
|
+
help="Admin operations",
|
|
42
|
+
)
|
|
43
|
+
sub = parser.add_subparsers(
|
|
44
|
+
dest="admin_command",
|
|
45
|
+
required=True,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# ── courses sub-group ──────────────────────────────────────────
|
|
49
|
+
_register_courses(sub)
|
|
50
|
+
|
|
51
|
+
# ── users sub-group ─────────────────────────────────────────────
|
|
52
|
+
_register_users(sub)
|
|
53
|
+
|
|
54
|
+
# ── agents sub-group ─────────────────────────────────────────────
|
|
55
|
+
_register_agents(sub)
|
|
56
|
+
|
|
57
|
+
# ── reports sub-group ─────────────────────────────────────────────
|
|
58
|
+
_register_reports(sub)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# ── Disabled handler ──────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _handle_disabled(args: argparse.Namespace) -> int: # noqa: ARG001
|
|
65
|
+
"""Exit with code 2 — admin is not enabled."""
|
|
66
|
+
print_err("No such command")
|
|
67
|
+
return 2
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ── Courses ────────────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _register_courses(sub: argparse._SubParsersAction) -> None:
|
|
74
|
+
"""Register the ``admin courses`` sub-group."""
|
|
75
|
+
courses = sub.add_parser(
|
|
76
|
+
"courses",
|
|
77
|
+
help="Administer courses",
|
|
78
|
+
)
|
|
79
|
+
courses_sub = courses.add_subparsers(
|
|
80
|
+
dest="admin_courses_command",
|
|
81
|
+
required=True,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# courses list
|
|
85
|
+
cl = courses_sub.add_parser(
|
|
86
|
+
"list",
|
|
87
|
+
help="List courses (admin view)",
|
|
88
|
+
parents=[COMMON_PARSER],
|
|
89
|
+
)
|
|
90
|
+
cl.add_argument("--status")
|
|
91
|
+
cl.add_argument("--owner-agent-id")
|
|
92
|
+
cl.add_argument("--limit", type=int)
|
|
93
|
+
cl.add_argument("--cursor")
|
|
94
|
+
cl.set_defaults(handler=handle_admin_courses_list)
|
|
95
|
+
|
|
96
|
+
# courses get
|
|
97
|
+
cg = courses_sub.add_parser(
|
|
98
|
+
"get",
|
|
99
|
+
help="Get course details (admin view)",
|
|
100
|
+
parents=[COMMON_PARSER],
|
|
101
|
+
)
|
|
102
|
+
cg.add_argument("course_id", metavar="COURSE_ID")
|
|
103
|
+
cg.set_defaults(handler=handle_admin_courses_get)
|
|
104
|
+
|
|
105
|
+
# courses block
|
|
106
|
+
cb = courses_sub.add_parser(
|
|
107
|
+
"block",
|
|
108
|
+
help="Block a course (set status to blocked)",
|
|
109
|
+
parents=[COMMON_PARSER],
|
|
110
|
+
)
|
|
111
|
+
cb.add_argument("course_id", metavar="COURSE_ID")
|
|
112
|
+
cb.add_argument("--yes", action="store_true")
|
|
113
|
+
cb.set_defaults(handler=handle_admin_courses_block)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def handle_admin_courses_list(args: argparse.Namespace) -> int:
|
|
117
|
+
"""Execute the admin courses list command."""
|
|
118
|
+
if args.owner_agent_id is not None:
|
|
119
|
+
bad_id = validate_uuid_id(args.owner_agent_id, "--owner-agent-id")
|
|
120
|
+
if bad_id is not None:
|
|
121
|
+
return bad_id
|
|
122
|
+
config = resolve_config_from_args(args)
|
|
123
|
+
client = make_client(config)
|
|
124
|
+
try:
|
|
125
|
+
kwargs = only_not_none(
|
|
126
|
+
{},
|
|
127
|
+
status=args.status,
|
|
128
|
+
owner_agent_id=args.owner_agent_id,
|
|
129
|
+
limit=args.limit,
|
|
130
|
+
cursor=args.cursor,
|
|
131
|
+
)
|
|
132
|
+
result = client.v1.admin.list_courses(**kwargs)
|
|
133
|
+
emit(result, json_output=config.json_output)
|
|
134
|
+
except Exception as exc:
|
|
135
|
+
return handle_error(exc)
|
|
136
|
+
else:
|
|
137
|
+
return 0
|
|
138
|
+
finally:
|
|
139
|
+
client.close()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def handle_admin_courses_get(args: argparse.Namespace) -> int:
|
|
143
|
+
"""Execute the admin courses get command."""
|
|
144
|
+
bad_id = validate_uuid_id(args.course_id, "COURSE_ID")
|
|
145
|
+
if bad_id is not None:
|
|
146
|
+
return bad_id
|
|
147
|
+
config = resolve_config_from_args(args)
|
|
148
|
+
client = make_client(config)
|
|
149
|
+
try:
|
|
150
|
+
result = client.v1.admin.get_course(course_id=args.course_id)
|
|
151
|
+
emit(result, json_output=config.json_output)
|
|
152
|
+
except Exception as exc:
|
|
153
|
+
return handle_error(exc)
|
|
154
|
+
else:
|
|
155
|
+
return 0
|
|
156
|
+
finally:
|
|
157
|
+
client.close()
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def handle_admin_courses_block(args: argparse.Namespace) -> int:
|
|
161
|
+
"""Execute the admin courses block command."""
|
|
162
|
+
bad_id = validate_uuid_id(args.course_id, "COURSE_ID")
|
|
163
|
+
if bad_id is not None:
|
|
164
|
+
return bad_id
|
|
165
|
+
refusal = require_yes(args.yes, "block this course")
|
|
166
|
+
if refusal is not None:
|
|
167
|
+
return refusal
|
|
168
|
+
config = resolve_config_from_args(args)
|
|
169
|
+
client = make_client(config)
|
|
170
|
+
try:
|
|
171
|
+
result = client.v1.admin.update_course_status(course_id=args.course_id)
|
|
172
|
+
emit(result, json_output=config.json_output)
|
|
173
|
+
except Exception as exc:
|
|
174
|
+
return handle_error(exc)
|
|
175
|
+
else:
|
|
176
|
+
return 0
|
|
177
|
+
finally:
|
|
178
|
+
client.close()
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# ── Users ──────────────────────────────────────────────────────────
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _register_users(sub: argparse._SubParsersAction) -> None:
|
|
185
|
+
"""Register the ``admin users`` sub-group."""
|
|
186
|
+
users = sub.add_parser(
|
|
187
|
+
"users",
|
|
188
|
+
help="Administer users",
|
|
189
|
+
)
|
|
190
|
+
users_sub = users.add_subparsers(
|
|
191
|
+
dest="admin_users_command",
|
|
192
|
+
required=True,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# users get
|
|
196
|
+
ug = users_sub.add_parser(
|
|
197
|
+
"get",
|
|
198
|
+
help="Get user details",
|
|
199
|
+
parents=[COMMON_PARSER],
|
|
200
|
+
)
|
|
201
|
+
ug.add_argument("user_id", metavar="USER_ID")
|
|
202
|
+
ug.set_defaults(handler=handle_admin_users_get)
|
|
203
|
+
|
|
204
|
+
# users suspend
|
|
205
|
+
us = users_sub.add_parser(
|
|
206
|
+
"suspend",
|
|
207
|
+
help="Suspend a user",
|
|
208
|
+
parents=[COMMON_PARSER],
|
|
209
|
+
)
|
|
210
|
+
us.add_argument("user_id", metavar="USER_ID")
|
|
211
|
+
us.add_argument("--yes", action="store_true")
|
|
212
|
+
us.set_defaults(handler=handle_admin_users_suspend)
|
|
213
|
+
|
|
214
|
+
# users unsuspend
|
|
215
|
+
uus = users_sub.add_parser(
|
|
216
|
+
"unsuspend",
|
|
217
|
+
help="Unsuspend a user",
|
|
218
|
+
parents=[COMMON_PARSER],
|
|
219
|
+
)
|
|
220
|
+
uus.add_argument("user_id", metavar="USER_ID")
|
|
221
|
+
uus.add_argument("--yes", action="store_true")
|
|
222
|
+
uus.set_defaults(handler=handle_admin_users_unsuspend)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def handle_admin_users_get(args: argparse.Namespace) -> int:
|
|
226
|
+
"""Execute the admin users get command."""
|
|
227
|
+
bad_id = validate_uuid_id(args.user_id, "USER_ID")
|
|
228
|
+
if bad_id is not None:
|
|
229
|
+
return bad_id
|
|
230
|
+
config = resolve_config_from_args(args)
|
|
231
|
+
client = make_client(config)
|
|
232
|
+
try:
|
|
233
|
+
result = client.v1.admin.get_user(user_id=args.user_id)
|
|
234
|
+
emit(result, json_output=config.json_output)
|
|
235
|
+
except Exception as exc:
|
|
236
|
+
return handle_error(exc)
|
|
237
|
+
else:
|
|
238
|
+
return 0
|
|
239
|
+
finally:
|
|
240
|
+
client.close()
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def handle_admin_users_suspend(args: argparse.Namespace) -> int:
|
|
244
|
+
"""Execute the admin users suspend command."""
|
|
245
|
+
bad_id = validate_uuid_id(args.user_id, "USER_ID")
|
|
246
|
+
if bad_id is not None:
|
|
247
|
+
return bad_id
|
|
248
|
+
refusal = require_yes(args.yes, "suspend this user")
|
|
249
|
+
if refusal is not None:
|
|
250
|
+
return refusal
|
|
251
|
+
config = resolve_config_from_args(args)
|
|
252
|
+
client = make_client(config)
|
|
253
|
+
try:
|
|
254
|
+
result = client.v1.admin.suspend_user(user_id=args.user_id)
|
|
255
|
+
emit(result, json_output=config.json_output)
|
|
256
|
+
except Exception as exc:
|
|
257
|
+
return handle_error(exc)
|
|
258
|
+
else:
|
|
259
|
+
return 0
|
|
260
|
+
finally:
|
|
261
|
+
client.close()
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def handle_admin_users_unsuspend(args: argparse.Namespace) -> int:
|
|
265
|
+
"""Execute the admin users unsuspend command."""
|
|
266
|
+
bad_id = validate_uuid_id(args.user_id, "USER_ID")
|
|
267
|
+
if bad_id is not None:
|
|
268
|
+
return bad_id
|
|
269
|
+
refusal = require_yes(args.yes, "unsuspend this user")
|
|
270
|
+
if refusal is not None:
|
|
271
|
+
return refusal
|
|
272
|
+
config = resolve_config_from_args(args)
|
|
273
|
+
client = make_client(config)
|
|
274
|
+
try:
|
|
275
|
+
result = client.v1.admin.unsuspend_user(user_id=args.user_id)
|
|
276
|
+
emit(result, json_output=config.json_output)
|
|
277
|
+
except Exception as exc:
|
|
278
|
+
return handle_error(exc)
|
|
279
|
+
else:
|
|
280
|
+
return 0
|
|
281
|
+
finally:
|
|
282
|
+
client.close()
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# ── Agents ─────────────────────────────────────────────────────────
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _register_agents(sub: argparse._SubParsersAction) -> None:
|
|
289
|
+
"""Register the ``admin agents`` sub-group."""
|
|
290
|
+
agents = sub.add_parser(
|
|
291
|
+
"agents",
|
|
292
|
+
help="Administer agents",
|
|
293
|
+
)
|
|
294
|
+
agents_sub = agents.add_subparsers(
|
|
295
|
+
dest="admin_agents_command",
|
|
296
|
+
required=True,
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# agents get
|
|
300
|
+
ag = agents_sub.add_parser(
|
|
301
|
+
"get",
|
|
302
|
+
help="Get agent details",
|
|
303
|
+
parents=[COMMON_PARSER],
|
|
304
|
+
)
|
|
305
|
+
ag.add_argument("agent_id", metavar="AGENT_ID")
|
|
306
|
+
ag.set_defaults(handler=handle_admin_agents_get)
|
|
307
|
+
|
|
308
|
+
# agents suspend
|
|
309
|
+
asp = agents_sub.add_parser(
|
|
310
|
+
"suspend",
|
|
311
|
+
help="Suspend an agent",
|
|
312
|
+
parents=[COMMON_PARSER],
|
|
313
|
+
)
|
|
314
|
+
asp.add_argument("agent_id", metavar="AGENT_ID")
|
|
315
|
+
asp.add_argument("--yes", action="store_true")
|
|
316
|
+
asp.set_defaults(handler=handle_admin_agents_suspend)
|
|
317
|
+
|
|
318
|
+
# agents unsuspend
|
|
319
|
+
aus = agents_sub.add_parser(
|
|
320
|
+
"unsuspend",
|
|
321
|
+
help="Unsuspend an agent",
|
|
322
|
+
parents=[COMMON_PARSER],
|
|
323
|
+
)
|
|
324
|
+
aus.add_argument("agent_id", metavar="AGENT_ID")
|
|
325
|
+
aus.add_argument("--yes", action="store_true")
|
|
326
|
+
aus.set_defaults(handler=handle_admin_agents_unsuspend)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def handle_admin_agents_get(args: argparse.Namespace) -> int:
|
|
330
|
+
"""Execute the admin agents get command."""
|
|
331
|
+
bad_id = validate_uuid_id(args.agent_id, "AGENT_ID")
|
|
332
|
+
if bad_id is not None:
|
|
333
|
+
return bad_id
|
|
334
|
+
config = resolve_config_from_args(args)
|
|
335
|
+
client = make_client(config)
|
|
336
|
+
try:
|
|
337
|
+
result = client.v1.admin.get_agent(agent_id=args.agent_id)
|
|
338
|
+
emit(result, json_output=config.json_output)
|
|
339
|
+
except Exception as exc:
|
|
340
|
+
return handle_error(exc)
|
|
341
|
+
else:
|
|
342
|
+
return 0
|
|
343
|
+
finally:
|
|
344
|
+
client.close()
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def handle_admin_agents_suspend(args: argparse.Namespace) -> int:
|
|
348
|
+
"""Execute the admin agents suspend command."""
|
|
349
|
+
bad_id = validate_uuid_id(args.agent_id, "AGENT_ID")
|
|
350
|
+
if bad_id is not None:
|
|
351
|
+
return bad_id
|
|
352
|
+
refusal = require_yes(args.yes, "suspend this agent")
|
|
353
|
+
if refusal is not None:
|
|
354
|
+
return refusal
|
|
355
|
+
config = resolve_config_from_args(args)
|
|
356
|
+
client = make_client(config)
|
|
357
|
+
try:
|
|
358
|
+
result = client.v1.admin.suspend_agent(agent_id=args.agent_id)
|
|
359
|
+
emit(result, json_output=config.json_output)
|
|
360
|
+
except Exception as exc:
|
|
361
|
+
return handle_error(exc)
|
|
362
|
+
else:
|
|
363
|
+
return 0
|
|
364
|
+
finally:
|
|
365
|
+
client.close()
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def handle_admin_agents_unsuspend(args: argparse.Namespace) -> int:
|
|
369
|
+
"""Execute the admin agents unsuspend command."""
|
|
370
|
+
bad_id = validate_uuid_id(args.agent_id, "AGENT_ID")
|
|
371
|
+
if bad_id is not None:
|
|
372
|
+
return bad_id
|
|
373
|
+
refusal = require_yes(args.yes, "unsuspend this agent")
|
|
374
|
+
if refusal is not None:
|
|
375
|
+
return refusal
|
|
376
|
+
config = resolve_config_from_args(args)
|
|
377
|
+
client = make_client(config)
|
|
378
|
+
try:
|
|
379
|
+
result = client.v1.admin.unsuspend_agent(agent_id=args.agent_id)
|
|
380
|
+
emit(result, json_output=config.json_output)
|
|
381
|
+
except Exception as exc:
|
|
382
|
+
return handle_error(exc)
|
|
383
|
+
else:
|
|
384
|
+
return 0
|
|
385
|
+
finally:
|
|
386
|
+
client.close()
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
# ── Reports ────────────────────────────────────────────────────────
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def _register_reports(sub: argparse._SubParsersAction) -> None:
|
|
393
|
+
"""Register the ``admin reports`` sub-group."""
|
|
394
|
+
reports = sub.add_parser(
|
|
395
|
+
"reports",
|
|
396
|
+
help="Administer reports",
|
|
397
|
+
)
|
|
398
|
+
reports_sub = reports.add_subparsers(
|
|
399
|
+
dest="admin_reports_command",
|
|
400
|
+
required=True,
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
# reports list
|
|
404
|
+
rl = reports_sub.add_parser(
|
|
405
|
+
"list",
|
|
406
|
+
help="List reports (admin view)",
|
|
407
|
+
parents=[COMMON_PARSER],
|
|
408
|
+
)
|
|
409
|
+
rl.add_argument("--status")
|
|
410
|
+
rl.add_argument("--severity")
|
|
411
|
+
rl.add_argument("--target-type")
|
|
412
|
+
rl.add_argument("--limit", type=int)
|
|
413
|
+
rl.add_argument("--cursor")
|
|
414
|
+
rl.set_defaults(handler=handle_admin_reports_list)
|
|
415
|
+
|
|
416
|
+
# reports get
|
|
417
|
+
rg = reports_sub.add_parser(
|
|
418
|
+
"get",
|
|
419
|
+
help="Get report details",
|
|
420
|
+
parents=[COMMON_PARSER],
|
|
421
|
+
)
|
|
422
|
+
rg.add_argument("report_id", metavar="REPORT_ID")
|
|
423
|
+
rg.set_defaults(handler=handle_admin_reports_get)
|
|
424
|
+
|
|
425
|
+
# reports resolve
|
|
426
|
+
rr = reports_sub.add_parser(
|
|
427
|
+
"resolve",
|
|
428
|
+
help="Resolve a report",
|
|
429
|
+
parents=[COMMON_PARSER],
|
|
430
|
+
)
|
|
431
|
+
rr.add_argument("report_id", metavar="REPORT_ID")
|
|
432
|
+
rr.add_argument("--note")
|
|
433
|
+
rr.add_argument("--yes", action="store_true")
|
|
434
|
+
rr.set_defaults(handler=handle_admin_reports_resolve)
|
|
435
|
+
|
|
436
|
+
# reports dismiss
|
|
437
|
+
rd = reports_sub.add_parser(
|
|
438
|
+
"dismiss",
|
|
439
|
+
help="Dismiss a report",
|
|
440
|
+
parents=[COMMON_PARSER],
|
|
441
|
+
)
|
|
442
|
+
rd.add_argument("report_id", metavar="REPORT_ID")
|
|
443
|
+
rd.add_argument("--reason", required=True)
|
|
444
|
+
rd.add_argument("--yes", action="store_true")
|
|
445
|
+
rd.set_defaults(handler=handle_admin_reports_dismiss)
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def handle_admin_reports_list(args: argparse.Namespace) -> int:
|
|
449
|
+
"""Execute the admin reports list command."""
|
|
450
|
+
config = resolve_config_from_args(args)
|
|
451
|
+
client = make_client(config)
|
|
452
|
+
try:
|
|
453
|
+
kwargs = only_not_none(
|
|
454
|
+
{},
|
|
455
|
+
status=args.status,
|
|
456
|
+
severity=args.severity,
|
|
457
|
+
target_type=args.target_type,
|
|
458
|
+
limit=args.limit,
|
|
459
|
+
cursor=args.cursor,
|
|
460
|
+
)
|
|
461
|
+
result = client.v1.admin.list_reports(**kwargs)
|
|
462
|
+
emit(result, json_output=config.json_output)
|
|
463
|
+
except Exception as exc:
|
|
464
|
+
return handle_error(exc)
|
|
465
|
+
else:
|
|
466
|
+
return 0
|
|
467
|
+
finally:
|
|
468
|
+
client.close()
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def handle_admin_reports_get(args: argparse.Namespace) -> int:
|
|
472
|
+
"""Execute the admin reports get command."""
|
|
473
|
+
bad_id = validate_uuid_id(args.report_id, "REPORT_ID")
|
|
474
|
+
if bad_id is not None:
|
|
475
|
+
return bad_id
|
|
476
|
+
config = resolve_config_from_args(args)
|
|
477
|
+
client = make_client(config)
|
|
478
|
+
try:
|
|
479
|
+
result = client.v1.admin.get_report(report_id=args.report_id)
|
|
480
|
+
emit(result, json_output=config.json_output)
|
|
481
|
+
except Exception as exc:
|
|
482
|
+
return handle_error(exc)
|
|
483
|
+
else:
|
|
484
|
+
return 0
|
|
485
|
+
finally:
|
|
486
|
+
client.close()
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def handle_admin_reports_resolve(args: argparse.Namespace) -> int:
|
|
490
|
+
"""Execute the admin reports resolve command."""
|
|
491
|
+
bad_id = validate_uuid_id(args.report_id, "REPORT_ID")
|
|
492
|
+
if bad_id is not None:
|
|
493
|
+
return bad_id
|
|
494
|
+
refusal = require_yes(args.yes, "resolve this report")
|
|
495
|
+
if refusal is not None:
|
|
496
|
+
return refusal
|
|
497
|
+
config = resolve_config_from_args(args)
|
|
498
|
+
client = make_client(config)
|
|
499
|
+
try:
|
|
500
|
+
kwargs = only_not_none(
|
|
501
|
+
{"report_id": args.report_id},
|
|
502
|
+
note=args.note,
|
|
503
|
+
)
|
|
504
|
+
result = client.v1.admin.resolve_report(**kwargs)
|
|
505
|
+
emit(result, json_output=config.json_output)
|
|
506
|
+
except Exception as exc:
|
|
507
|
+
return handle_error(exc)
|
|
508
|
+
else:
|
|
509
|
+
return 0
|
|
510
|
+
finally:
|
|
511
|
+
client.close()
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def handle_admin_reports_dismiss(args: argparse.Namespace) -> int:
|
|
515
|
+
"""Execute the admin reports dismiss command."""
|
|
516
|
+
bad_id = validate_uuid_id(args.report_id, "REPORT_ID")
|
|
517
|
+
if bad_id is not None:
|
|
518
|
+
return bad_id
|
|
519
|
+
refusal = require_yes(args.yes, "dismiss this report")
|
|
520
|
+
if refusal is not None:
|
|
521
|
+
return refusal
|
|
522
|
+
config = resolve_config_from_args(args)
|
|
523
|
+
client = make_client(config)
|
|
524
|
+
try:
|
|
525
|
+
result = client.v1.admin.dismiss_report(
|
|
526
|
+
report_id=args.report_id,
|
|
527
|
+
reason=args.reason,
|
|
528
|
+
)
|
|
529
|
+
emit(result, json_output=config.json_output)
|
|
530
|
+
except Exception as exc:
|
|
531
|
+
return handle_error(exc)
|
|
532
|
+
else:
|
|
533
|
+
return 0
|
|
534
|
+
finally:
|
|
535
|
+
client.close()
|