meshagent-cli 0.7.0__py3-none-any.whl → 0.23.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.
- meshagent/cli/agent.py +23 -13
- meshagent/cli/api_keys.py +4 -4
- meshagent/cli/async_typer.py +52 -4
- meshagent/cli/call.py +27 -36
- meshagent/cli/chatbot.py +1559 -177
- meshagent/cli/cli.py +23 -22
- meshagent/cli/cli_mcp.py +92 -28
- meshagent/cli/cli_secrets.py +10 -10
- meshagent/cli/common_options.py +19 -4
- meshagent/cli/containers.py +164 -16
- meshagent/cli/database.py +997 -0
- meshagent/cli/developer.py +3 -3
- meshagent/cli/exec.py +22 -6
- meshagent/cli/helper.py +101 -12
- meshagent/cli/helpers.py +65 -11
- meshagent/cli/host.py +41 -0
- meshagent/cli/mailbot.py +1104 -79
- meshagent/cli/mailboxes.py +223 -0
- meshagent/cli/meeting_transcriber.py +29 -15
- meshagent/cli/messaging.py +7 -10
- meshagent/cli/multi.py +357 -0
- meshagent/cli/oauth2.py +192 -40
- meshagent/cli/participant_token.py +5 -3
- meshagent/cli/port.py +70 -0
- meshagent/cli/queue.py +2 -2
- meshagent/cli/room.py +24 -212
- meshagent/cli/rooms.py +214 -0
- meshagent/cli/services.py +269 -37
- meshagent/cli/sessions.py +5 -5
- meshagent/cli/storage.py +5 -5
- meshagent/cli/sync.py +434 -0
- meshagent/cli/task_runner.py +1317 -0
- meshagent/cli/version.py +1 -1
- meshagent/cli/voicebot.py +544 -98
- meshagent/cli/webhook.py +7 -7
- meshagent/cli/worker.py +1403 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/METADATA +15 -13
- meshagent_cli-0.23.0.dist-info/RECORD +45 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/WHEEL +1 -1
- meshagent_cli-0.7.0.dist-info/RECORD +0 -36
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/entry_points.txt +0 -0
- {meshagent_cli-0.7.0.dist-info → meshagent_cli-0.23.0.dist-info}/top_level.txt +0 -0
meshagent/cli/services.py
CHANGED
|
@@ -9,7 +9,7 @@ from aiohttp import ClientResponseError
|
|
|
9
9
|
import pathlib
|
|
10
10
|
from meshagent.cli import async_typer
|
|
11
11
|
from meshagent.api.services import well_known_service_path
|
|
12
|
-
from meshagent.api.specs.service import ServiceSpec
|
|
12
|
+
from meshagent.api.specs.service import ServiceSpec, ServiceTemplateSpec
|
|
13
13
|
from meshagent.api.keys import parse_api_key
|
|
14
14
|
|
|
15
15
|
import asyncio
|
|
@@ -35,27 +35,53 @@ from meshagent.api import (
|
|
|
35
35
|
)
|
|
36
36
|
from meshagent.cli.common_options import OutputFormatOption
|
|
37
37
|
|
|
38
|
+
from pydantic import RootModel
|
|
38
39
|
from pydantic_yaml import parse_yaml_raw_as
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
from meshagent.cli.call import _make_call
|
|
42
43
|
|
|
44
|
+
|
|
43
45
|
app = async_typer.AsyncTyper(help="Manage services for your project")
|
|
44
46
|
|
|
45
47
|
|
|
48
|
+
class ServiceTemplateValues(RootModel[dict[str, str]]):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _load_template_values(
|
|
53
|
+
values_file: Optional[str],
|
|
54
|
+
values: Optional[list[str]] = None,
|
|
55
|
+
) -> dict[str, str]:
|
|
56
|
+
template_values: dict[str, str] = {}
|
|
57
|
+
|
|
58
|
+
if values_file is not None:
|
|
59
|
+
with open(str(pathlib.Path(values_file).expanduser().resolve()), "rb") as f:
|
|
60
|
+
template_values = parse_yaml_raw_as(ServiceTemplateValues, f.read()).root
|
|
61
|
+
|
|
62
|
+
if values:
|
|
63
|
+
for item in values:
|
|
64
|
+
if "=" not in item:
|
|
65
|
+
raise typer.BadParameter("Template values must be key=value")
|
|
66
|
+
key, value = item.split("=", 1)
|
|
67
|
+
if not key:
|
|
68
|
+
raise typer.BadParameter("Template values must include a key")
|
|
69
|
+
template_values[key] = value
|
|
70
|
+
|
|
71
|
+
return template_values
|
|
72
|
+
|
|
73
|
+
|
|
46
74
|
@app.async_command("create")
|
|
47
75
|
async def service_create(
|
|
48
76
|
*,
|
|
49
|
-
project_id: ProjectIdOption
|
|
77
|
+
project_id: ProjectIdOption,
|
|
50
78
|
file: Annotated[
|
|
51
79
|
str,
|
|
52
80
|
typer.Option("--file", "-f", help="File path to a service definition"),
|
|
53
81
|
],
|
|
54
82
|
room: Annotated[
|
|
55
83
|
Optional[str],
|
|
56
|
-
typer.Option(
|
|
57
|
-
"--room", "-r", help="The name of a room to create the service for"
|
|
58
|
-
),
|
|
84
|
+
typer.Option("--room", help="The name of a room to create the service for"),
|
|
59
85
|
] = None,
|
|
60
86
|
):
|
|
61
87
|
"""Create a service attached to the project."""
|
|
@@ -94,7 +120,7 @@ async def service_create(
|
|
|
94
120
|
@app.async_command("update")
|
|
95
121
|
async def service_update(
|
|
96
122
|
*,
|
|
97
|
-
project_id: ProjectIdOption
|
|
123
|
+
project_id: ProjectIdOption,
|
|
98
124
|
id: Optional[str] = None,
|
|
99
125
|
file: Annotated[
|
|
100
126
|
str,
|
|
@@ -108,9 +134,7 @@ async def service_update(
|
|
|
108
134
|
] = False,
|
|
109
135
|
room: Annotated[
|
|
110
136
|
Optional[str],
|
|
111
|
-
typer.Option(
|
|
112
|
-
"--room", "-r", help="The name of a room to update the service for"
|
|
113
|
-
),
|
|
137
|
+
typer.Option("--room", help="The name of a room to update the service for"),
|
|
114
138
|
] = None,
|
|
115
139
|
):
|
|
116
140
|
"""Create a service attached to the project."""
|
|
@@ -176,10 +200,217 @@ async def service_update(
|
|
|
176
200
|
await client.close()
|
|
177
201
|
|
|
178
202
|
|
|
203
|
+
@app.async_command("validate")
|
|
204
|
+
async def service_validate(
|
|
205
|
+
*,
|
|
206
|
+
file: Annotated[
|
|
207
|
+
str,
|
|
208
|
+
typer.Option("--file", "-f", help="File path to a service definition"),
|
|
209
|
+
],
|
|
210
|
+
):
|
|
211
|
+
"""Validate a service spec from a YAML file."""
|
|
212
|
+
try:
|
|
213
|
+
with open(str(pathlib.Path(file).expanduser().resolve()), "rb") as f:
|
|
214
|
+
spec = parse_yaml_raw_as(ServiceSpec, f.read())
|
|
215
|
+
except Exception as exc:
|
|
216
|
+
print(f"[red]Invalid service spec: {exc}[/red]")
|
|
217
|
+
raise typer.Exit(code=1)
|
|
218
|
+
|
|
219
|
+
print(f"[green]Service spec is valid:[/] {spec.metadata.name}")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@app.async_command("create-template")
|
|
223
|
+
async def service_create_template(
|
|
224
|
+
*,
|
|
225
|
+
project_id: ProjectIdOption,
|
|
226
|
+
file: Annotated[
|
|
227
|
+
str,
|
|
228
|
+
typer.Option("--file", "-f", help="File path to a service template"),
|
|
229
|
+
],
|
|
230
|
+
values: Annotated[
|
|
231
|
+
Optional[str],
|
|
232
|
+
typer.Option("--values-file", help="File path to template values"),
|
|
233
|
+
] = None,
|
|
234
|
+
value: Annotated[
|
|
235
|
+
Optional[list[str]],
|
|
236
|
+
typer.Option(
|
|
237
|
+
"--value",
|
|
238
|
+
"-v",
|
|
239
|
+
help="Template value override (key=value)",
|
|
240
|
+
),
|
|
241
|
+
] = None,
|
|
242
|
+
room: Annotated[
|
|
243
|
+
Optional[str],
|
|
244
|
+
typer.Option("--room", help="The name of a room to create the service for"),
|
|
245
|
+
] = None,
|
|
246
|
+
):
|
|
247
|
+
"""Create a service from a ServiceTemplate spec."""
|
|
248
|
+
client = await get_client()
|
|
249
|
+
try:
|
|
250
|
+
project_id = await resolve_project_id(project_id)
|
|
251
|
+
|
|
252
|
+
with open(str(pathlib.Path(file).expanduser().resolve()), "rb") as f:
|
|
253
|
+
template = f.read()
|
|
254
|
+
|
|
255
|
+
template_values = _load_template_values(values, value)
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
if room is None:
|
|
259
|
+
service = await client.create_service_from_template(
|
|
260
|
+
project_id=project_id, template=template, values=template_values
|
|
261
|
+
)
|
|
262
|
+
else:
|
|
263
|
+
service = await client.create_room_service_from_template(
|
|
264
|
+
project_id=project_id,
|
|
265
|
+
template=template,
|
|
266
|
+
values=template_values,
|
|
267
|
+
room_name=room,
|
|
268
|
+
)
|
|
269
|
+
except ClientResponseError as exc:
|
|
270
|
+
if exc.status == 409:
|
|
271
|
+
print(
|
|
272
|
+
f"[red]Service name already in use: {template.metadata.name}[/red]"
|
|
273
|
+
)
|
|
274
|
+
raise typer.Exit(code=1)
|
|
275
|
+
raise
|
|
276
|
+
else:
|
|
277
|
+
service_id = service.id or ""
|
|
278
|
+
print(f"[green]Created service:[/] {service_id}")
|
|
279
|
+
|
|
280
|
+
finally:
|
|
281
|
+
await client.close()
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@app.async_command("update-template")
|
|
285
|
+
async def service_update_template(
|
|
286
|
+
*,
|
|
287
|
+
project_id: ProjectIdOption,
|
|
288
|
+
id: Optional[str] = None,
|
|
289
|
+
file: Annotated[
|
|
290
|
+
str,
|
|
291
|
+
typer.Option("--file", "-f", help="File path to a service template"),
|
|
292
|
+
],
|
|
293
|
+
values: Annotated[
|
|
294
|
+
Optional[str],
|
|
295
|
+
typer.Option("--values-file", help="File path to template values"),
|
|
296
|
+
] = None,
|
|
297
|
+
value: Annotated[
|
|
298
|
+
Optional[list[str]],
|
|
299
|
+
typer.Option(
|
|
300
|
+
"--value",
|
|
301
|
+
"-v",
|
|
302
|
+
help="Template value override (key=value)",
|
|
303
|
+
),
|
|
304
|
+
] = None,
|
|
305
|
+
create: Annotated[
|
|
306
|
+
Optional[bool],
|
|
307
|
+
typer.Option(
|
|
308
|
+
help="create the service if it does not exist",
|
|
309
|
+
),
|
|
310
|
+
] = False,
|
|
311
|
+
room: Annotated[
|
|
312
|
+
Optional[str],
|
|
313
|
+
typer.Option("--room", help="The name of a room to update the service for"),
|
|
314
|
+
] = None,
|
|
315
|
+
):
|
|
316
|
+
"""Update a service using a ServiceTemplate spec."""
|
|
317
|
+
client = await get_client()
|
|
318
|
+
try:
|
|
319
|
+
project_id = await resolve_project_id(project_id)
|
|
320
|
+
|
|
321
|
+
with open(str(pathlib.Path(file).expanduser().resolve()), "rb") as f:
|
|
322
|
+
template = f.read()
|
|
323
|
+
|
|
324
|
+
template_values = _load_template_values(values, value)
|
|
325
|
+
|
|
326
|
+
try:
|
|
327
|
+
if id is None:
|
|
328
|
+
if room is None:
|
|
329
|
+
services = await client.list_services(project_id=project_id)
|
|
330
|
+
else:
|
|
331
|
+
services = await client.list_room_services(
|
|
332
|
+
project_id=project_id, room_name=room
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
for s in services:
|
|
336
|
+
if s.metadata.name == template.metadata.name:
|
|
337
|
+
id = s.id
|
|
338
|
+
|
|
339
|
+
if id is None and not create:
|
|
340
|
+
print("[red]pass a service id or specify --create[/red]")
|
|
341
|
+
raise typer.Exit(code=1)
|
|
342
|
+
|
|
343
|
+
if id is None:
|
|
344
|
+
if room is None:
|
|
345
|
+
service = await client.create_service_from_template(
|
|
346
|
+
project_id=project_id,
|
|
347
|
+
template=template,
|
|
348
|
+
values=template_values,
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
service = await client.create_room_service_from_template(
|
|
352
|
+
project_id=project_id,
|
|
353
|
+
template=template,
|
|
354
|
+
values=template_values,
|
|
355
|
+
room_name=room,
|
|
356
|
+
)
|
|
357
|
+
id = service.id
|
|
358
|
+
else:
|
|
359
|
+
if room is None:
|
|
360
|
+
service = await client.update_service_from_template(
|
|
361
|
+
project_id=project_id,
|
|
362
|
+
service_id=id,
|
|
363
|
+
template=template,
|
|
364
|
+
values=template_values,
|
|
365
|
+
)
|
|
366
|
+
else:
|
|
367
|
+
service = await client.update_room_service_from_template(
|
|
368
|
+
project_id=project_id,
|
|
369
|
+
service_id=id,
|
|
370
|
+
template=template,
|
|
371
|
+
values=template_values,
|
|
372
|
+
room_name=room,
|
|
373
|
+
)
|
|
374
|
+
if service.id is not None:
|
|
375
|
+
id = service.id
|
|
376
|
+
|
|
377
|
+
except ClientResponseError as exc:
|
|
378
|
+
if exc.status == 409:
|
|
379
|
+
print(
|
|
380
|
+
f"[red]Service name already in use: {template.metadata.name}[/red]"
|
|
381
|
+
)
|
|
382
|
+
raise typer.Exit(code=1)
|
|
383
|
+
raise
|
|
384
|
+
else:
|
|
385
|
+
print(f"[green]Updated service:[/] {id}")
|
|
386
|
+
|
|
387
|
+
finally:
|
|
388
|
+
await client.close()
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
@app.async_command("validate-template")
|
|
392
|
+
async def service_validate_template(
|
|
393
|
+
*,
|
|
394
|
+
file: Annotated[
|
|
395
|
+
str,
|
|
396
|
+
typer.Option("--file", "-f", help="File path to a service template"),
|
|
397
|
+
],
|
|
398
|
+
):
|
|
399
|
+
"""Validate a service template from a YAML file."""
|
|
400
|
+
try:
|
|
401
|
+
with open(str(pathlib.Path(file).expanduser().resolve()), "rb") as f:
|
|
402
|
+
template = parse_yaml_raw_as(ServiceTemplateSpec, f.read())
|
|
403
|
+
except Exception as exc:
|
|
404
|
+
print(f"[red]Invalid service template: {exc}[/red]")
|
|
405
|
+
raise typer.Exit(code=1)
|
|
406
|
+
|
|
407
|
+
print(f"[green]Service template is valid:[/] {template.metadata.name}")
|
|
408
|
+
|
|
409
|
+
|
|
179
410
|
@app.async_command("run")
|
|
180
411
|
async def service_run(
|
|
181
412
|
*,
|
|
182
|
-
project_id: ProjectIdOption
|
|
413
|
+
project_id: ProjectIdOption,
|
|
183
414
|
command: str,
|
|
184
415
|
port: Annotated[
|
|
185
416
|
int,
|
|
@@ -238,11 +469,26 @@ async def service_run(
|
|
|
238
469
|
run_tasks = []
|
|
239
470
|
|
|
240
471
|
async def run_service(port: int):
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
472
|
+
if command.endswith(".py"):
|
|
473
|
+
code, output = await _run_process(
|
|
474
|
+
cmd=shlex.split("python3 " + command),
|
|
475
|
+
log=True,
|
|
476
|
+
env={**os.environ, "MESHAGENT_PORT": str(port)},
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
elif command.endswith(".dart"):
|
|
480
|
+
code, output = await _run_process(
|
|
481
|
+
cmd=shlex.split("dart run " + command),
|
|
482
|
+
log=True,
|
|
483
|
+
env={**os.environ, "MESHAGENT_PORT": str(port)},
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
else:
|
|
487
|
+
code, output = await _run_process(
|
|
488
|
+
cmd=shlex.split(command),
|
|
489
|
+
log=True,
|
|
490
|
+
env={**os.environ, "MESHAGENT_PORT": str(port)},
|
|
491
|
+
)
|
|
246
492
|
|
|
247
493
|
if code != 0:
|
|
248
494
|
print(f"[red]{output}[/red]")
|
|
@@ -274,11 +520,12 @@ async def service_run(
|
|
|
274
520
|
print("[red]unable to read service spec[/red]")
|
|
275
521
|
raise typer.Exit(-1)
|
|
276
522
|
|
|
523
|
+
print(f"getting spec {port}", flush=True)
|
|
277
524
|
spec = await get_spec(port)
|
|
278
525
|
|
|
279
526
|
sys.stdout.write("\n")
|
|
280
527
|
|
|
281
|
-
for p in spec.ports:
|
|
528
|
+
for p in spec.ports or []:
|
|
282
529
|
print(f"[bold green]Connecting port {p.num}...[/bold green]")
|
|
283
530
|
|
|
284
531
|
for endpoint in p.endpoints:
|
|
@@ -319,7 +566,7 @@ async def service_run(
|
|
|
319
566
|
@app.async_command("show")
|
|
320
567
|
async def service_show(
|
|
321
568
|
*,
|
|
322
|
-
project_id: ProjectIdOption
|
|
569
|
+
project_id: ProjectIdOption,
|
|
323
570
|
service_id: Annotated[str, typer.Argument(help="ID of the service to show")],
|
|
324
571
|
):
|
|
325
572
|
"""Show a services for the project."""
|
|
@@ -337,13 +584,11 @@ async def service_show(
|
|
|
337
584
|
@app.async_command("list")
|
|
338
585
|
async def service_list(
|
|
339
586
|
*,
|
|
340
|
-
project_id: ProjectIdOption
|
|
587
|
+
project_id: ProjectIdOption,
|
|
341
588
|
o: OutputFormatOption = "table",
|
|
342
589
|
room: Annotated[
|
|
343
590
|
Optional[str],
|
|
344
|
-
typer.Option(
|
|
345
|
-
"--room", "-r", help="The name of a room to list the services for"
|
|
346
|
-
),
|
|
591
|
+
typer.Option("--room", help="The name of a room to list the services for"),
|
|
347
592
|
] = None,
|
|
348
593
|
):
|
|
349
594
|
"""List all services for the project."""
|
|
@@ -359,9 +604,7 @@ async def service_list(
|
|
|
359
604
|
)
|
|
360
605
|
|
|
361
606
|
if o == "json":
|
|
362
|
-
print(
|
|
363
|
-
{"services": [svc.model_dump(mode="json") for svc in services]}
|
|
364
|
-
).model_dump_json(indent=2)
|
|
607
|
+
print({"services": [svc.model_dump(mode="json") for svc in services]})
|
|
365
608
|
else:
|
|
366
609
|
print_json_table(
|
|
367
610
|
[
|
|
@@ -385,25 +628,14 @@ async def service_list(
|
|
|
385
628
|
@app.async_command("delete")
|
|
386
629
|
async def service_delete(
|
|
387
630
|
*,
|
|
388
|
-
project_id: ProjectIdOption
|
|
631
|
+
project_id: ProjectIdOption,
|
|
389
632
|
service_id: Annotated[str, typer.Argument(help="ID of the service to delete")],
|
|
390
|
-
room: Annotated[
|
|
391
|
-
Optional[str],
|
|
392
|
-
typer.Option(
|
|
393
|
-
"--room", "-r", help="The name of a room to delete the service for"
|
|
394
|
-
),
|
|
395
|
-
] = None,
|
|
396
633
|
):
|
|
397
634
|
"""Delete a service."""
|
|
398
635
|
client = await get_client()
|
|
399
636
|
try:
|
|
400
637
|
project_id = await resolve_project_id(project_id)
|
|
401
|
-
|
|
402
|
-
await client.delete_service(project_id=project_id, service_id=service_id)
|
|
403
|
-
else:
|
|
404
|
-
await client.delete_service(
|
|
405
|
-
project_id=project_id, service_id=service_id, room_name=room
|
|
406
|
-
)
|
|
638
|
+
await client.delete_service(project_id=project_id, service_id=service_id)
|
|
407
639
|
print(f"[green]Service {service_id} deleted.[/]")
|
|
408
640
|
finally:
|
|
409
641
|
await client.close()
|
meshagent/cli/sessions.py
CHANGED
|
@@ -2,11 +2,11 @@ from meshagent.cli import async_typer
|
|
|
2
2
|
from meshagent.cli.helper import get_client, print_json_table, resolve_project_id
|
|
3
3
|
from meshagent.cli.common_options import ProjectIdOption
|
|
4
4
|
|
|
5
|
-
app = async_typer.AsyncTyper()
|
|
5
|
+
app = async_typer.AsyncTyper(help="Inspect recent sessions and events")
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
@app.async_command("list")
|
|
9
|
-
async def list(*, project_id: ProjectIdOption
|
|
8
|
+
@app.async_command("list", help="List recent sessions")
|
|
9
|
+
async def list(*, project_id: ProjectIdOption):
|
|
10
10
|
client = await get_client()
|
|
11
11
|
sessions = await client.list_recent_sessions(
|
|
12
12
|
project_id=await resolve_project_id(project_id=project_id)
|
|
@@ -15,8 +15,8 @@ async def list(*, project_id: ProjectIdOption = None):
|
|
|
15
15
|
await client.close()
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
@app.async_command("show")
|
|
19
|
-
async def show(*, project_id: ProjectIdOption
|
|
18
|
+
@app.async_command("show", help="Show events for a session")
|
|
19
|
+
async def show(*, project_id: ProjectIdOption, session_id: str):
|
|
20
20
|
client = await get_client()
|
|
21
21
|
events = await client.list_session_events(
|
|
22
22
|
project_id=await resolve_project_id(project_id=project_id),
|
meshagent/cli/storage.py
CHANGED
|
@@ -55,7 +55,7 @@ def split_glob_subpath(subpath: str):
|
|
|
55
55
|
@app.async_command("exists")
|
|
56
56
|
async def storage_exists_command(
|
|
57
57
|
*,
|
|
58
|
-
project_id: ProjectIdOption
|
|
58
|
+
project_id: ProjectIdOption,
|
|
59
59
|
room: RoomOption,
|
|
60
60
|
path: str,
|
|
61
61
|
):
|
|
@@ -89,7 +89,7 @@ async def storage_exists_command(
|
|
|
89
89
|
@app.async_command("cp")
|
|
90
90
|
async def storage_cp_command(
|
|
91
91
|
*,
|
|
92
|
-
project_id: ProjectIdOption
|
|
92
|
+
project_id: ProjectIdOption,
|
|
93
93
|
room: RoomOption,
|
|
94
94
|
source_path: str,
|
|
95
95
|
dest_path: str,
|
|
@@ -322,7 +322,7 @@ async def storage_cp_command(
|
|
|
322
322
|
@app.async_command("show")
|
|
323
323
|
async def storage_show_command(
|
|
324
324
|
*,
|
|
325
|
-
project_id: ProjectIdOption
|
|
325
|
+
project_id: ProjectIdOption,
|
|
326
326
|
room: RoomOption,
|
|
327
327
|
path: str,
|
|
328
328
|
encoding: Annotated[
|
|
@@ -395,7 +395,7 @@ async def storage_show_command(
|
|
|
395
395
|
@app.async_command("rm")
|
|
396
396
|
async def storage_rm_command(
|
|
397
397
|
*,
|
|
398
|
-
project_id: ProjectIdOption
|
|
398
|
+
project_id: ProjectIdOption,
|
|
399
399
|
room: RoomOption,
|
|
400
400
|
path: str,
|
|
401
401
|
recursive: Annotated[
|
|
@@ -599,7 +599,7 @@ async def storage_rm_command(
|
|
|
599
599
|
@app.async_command("ls")
|
|
600
600
|
async def storage_ls_command(
|
|
601
601
|
*,
|
|
602
|
-
project_id: ProjectIdOption
|
|
602
|
+
project_id: ProjectIdOption,
|
|
603
603
|
room: RoomOption,
|
|
604
604
|
path: Annotated[
|
|
605
605
|
str, typer.Argument(..., help="Path to list (local or room://...)")
|