meshagent-cli 0.0.36__py3-none-any.whl → 0.0.38__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.

Potentially problematic release.


This version of meshagent-cli might be problematic. Click here for more details.

meshagent/cli/cli_mcp.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  from mcp.client.session import ClientSession
3
2
  from mcp.client.sse import sse_client
4
3
  from mcp.client.stdio import stdio_client, StdioServerParameters
@@ -8,14 +7,19 @@ from rich import print
8
7
  from typing import Annotated, Optional, List
9
8
 
10
9
  from meshagent.api.helpers import meshagent_base_url, websocket_room_url
11
- from meshagent.api import RoomClient, ParticipantToken, WebSocketClientProtocol, RoomException
10
+ from meshagent.api import RoomClient, WebSocketClientProtocol, RoomException
12
11
  from meshagent.cli import async_typer
13
- from meshagent.cli.helper import get_client, resolve_project_id, resolve_api_key, resolve_token_jwt, resolve_room
12
+ from meshagent.cli.helper import (
13
+ get_client,
14
+ resolve_project_id,
15
+ resolve_api_key,
16
+ resolve_token_jwt,
17
+ resolve_room,
18
+ )
14
19
 
15
- from meshagent.tools.hosting import RemoteToolkit, RemoteToolkitServer
20
+ from meshagent.tools.hosting import RemoteToolkit
16
21
 
17
22
  from meshagent.mcp import MCPToolkit
18
- from pathlib import Path
19
23
 
20
24
  from meshagent.api.services import ServiceHost
21
25
  import os
@@ -25,9 +29,20 @@ import shlex
25
29
 
26
30
  app = async_typer.AsyncTyper()
27
31
 
32
+
28
33
  @app.async_command("sse")
29
- async def sse(*, project_id: str = None, room: Annotated[str, typer.Option()], token_path: Annotated[Optional[str], typer.Option()] = None, api_key_id: Annotated[Optional[str], typer.Option()] = None, name: Annotated[str, typer.Option(..., help="Participant name")] = "cli", role: str = "tool", url: Annotated[str, typer.Option()], toolkit_name: Annotated[Optional[str], typer.Option()] = None):
30
- if toolkit_name == None:
34
+ async def sse(
35
+ *,
36
+ project_id: str = None,
37
+ room: Annotated[str, typer.Option()],
38
+ token_path: Annotated[Optional[str], typer.Option()] = None,
39
+ api_key_id: Annotated[Optional[str], typer.Option()] = None,
40
+ name: Annotated[str, typer.Option(..., help="Participant name")] = "cli",
41
+ role: str = "tool",
42
+ url: Annotated[str, typer.Option()],
43
+ toolkit_name: Annotated[Optional[str], typer.Option()] = None,
44
+ ):
45
+ if toolkit_name is None:
31
46
  toolkit_name = "mcp"
32
47
 
33
48
  account_client = await get_client()
@@ -36,20 +51,40 @@ async def sse(*, project_id: str = None, room: Annotated[str, typer.Option()], t
36
51
  api_key_id = await resolve_api_key(project_id, api_key_id)
37
52
 
38
53
  room = resolve_room(room)
39
- jwt = await resolve_token_jwt(project_id=project_id, api_key_id=api_key_id, token_path=token_path, name=name, role=role, room=room)
40
-
54
+ jwt = await resolve_token_jwt(
55
+ project_id=project_id,
56
+ api_key_id=api_key_id,
57
+ token_path=token_path,
58
+ name=name,
59
+ role=role,
60
+ room=room,
61
+ )
62
+
41
63
  print("[bold green]Connecting to room...[/bold green]")
42
- async with RoomClient(protocol=WebSocketClientProtocol(url=websocket_room_url(room_name=room, base_url=meshagent_base_url()), token=jwt)) as client:
43
-
64
+ async with RoomClient(
65
+ protocol=WebSocketClientProtocol(
66
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
67
+ token=jwt,
68
+ )
69
+ ) as client:
44
70
  async with sse_client(url) as (read_stream, write_stream):
45
-
46
- async with ClientSession(read_stream=read_stream, write_stream=write_stream) as session:
47
-
71
+ async with ClientSession(
72
+ read_stream=read_stream, write_stream=write_stream
73
+ ) as session:
48
74
  mcp_tools_response = await session.list_tools()
49
-
50
- toolkit = MCPToolkit(name=toolkit_name, session=session, tools=mcp_tools_response.tools)
51
-
52
- remote_toolkit = RemoteToolkit(name=toolkit.name, tools=toolkit.tools, title=toolkit.title, description=toolkit.description)
75
+
76
+ toolkit = MCPToolkit(
77
+ name=toolkit_name,
78
+ session=session,
79
+ tools=mcp_tools_response.tools,
80
+ )
81
+
82
+ remote_toolkit = RemoteToolkit(
83
+ name=toolkit.name,
84
+ tools=toolkit.tools,
85
+ title=toolkit.title,
86
+ description=toolkit.description,
87
+ )
53
88
 
54
89
  await remote_toolkit.start(room=client)
55
90
  try:
@@ -57,15 +92,26 @@ async def sse(*, project_id: str = None, room: Annotated[str, typer.Option()], t
57
92
  except KeyboardInterrupt:
58
93
  await remote_toolkit.stop()
59
94
 
60
-
61
95
  except RoomException as e:
62
96
  print(f"[red]{e}[/red]")
63
97
  finally:
64
98
  await account_client.close()
65
99
 
100
+
66
101
  @app.async_command("stdio")
67
- async def stdio(*, project_id: str = None, room: Annotated[str, typer.Option()], token_path: Annotated[Optional[str], typer.Option()] = None, api_key_id: Annotated[Optional[str], typer.Option()] = None, name: Annotated[str, typer.Option(..., help="Participant name")] = "cli", role: str = "tool", command: Annotated[str, typer.Option()], toolkit_name: Annotated[Optional[str], typer.Option()] = None, env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = []):
68
- if toolkit_name == None:
102
+ async def stdio(
103
+ *,
104
+ project_id: str = None,
105
+ room: Annotated[str, typer.Option()],
106
+ token_path: Annotated[Optional[str], typer.Option()] = None,
107
+ api_key_id: Annotated[Optional[str], typer.Option()] = None,
108
+ name: Annotated[str, typer.Option(..., help="Participant name")] = "cli",
109
+ role: str = "tool",
110
+ command: Annotated[str, typer.Option()],
111
+ toolkit_name: Annotated[Optional[str], typer.Option()] = None,
112
+ env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = [],
113
+ ):
114
+ if toolkit_name is None:
69
115
  toolkit_name = "mcp"
70
116
 
71
117
  account_client = await get_client()
@@ -74,26 +120,50 @@ async def stdio(*, project_id: str = None, room: Annotated[str, typer.Option()],
74
120
  api_key_id = await resolve_api_key(project_id, api_key_id)
75
121
 
76
122
  room = resolve_room(room)
77
- jwt = await resolve_token_jwt(project_id=project_id, api_key_id=api_key_id, token_path=token_path, name=name, role=role, room=room)
123
+ jwt = await resolve_token_jwt(
124
+ project_id=project_id,
125
+ api_key_id=api_key_id,
126
+ token_path=token_path,
127
+ name=name,
128
+ role=role,
129
+ room=room,
130
+ )
78
131
 
79
132
  print("[bold green]Connecting to room...[/bold green]")
80
- async with RoomClient(protocol=WebSocketClientProtocol(url=websocket_room_url(room_name=room, base_url=meshagent_base_url()), token=jwt)) as client:
81
-
133
+ async with RoomClient(
134
+ protocol=WebSocketClientProtocol(
135
+ url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
136
+ token=jwt,
137
+ )
138
+ ) as client:
82
139
  parsed_command = shlex.split(command)
83
140
 
84
- async with stdio_client(StdioServerParameters(
85
- command=parsed_command[0], # Executable
86
- args=parsed_command[1:], # Optional command line arguments
87
- env=_kv_to_dict(env), # Optional environment variables
88
- )) as (read_stream, write_stream):
89
-
90
- async with ClientSession(read_stream=read_stream, write_stream=write_stream) as session:
91
-
141
+ async with (
142
+ stdio_client(
143
+ StdioServerParameters(
144
+ command=parsed_command[0], # Executable
145
+ args=parsed_command[1:], # Optional command line arguments
146
+ env=_kv_to_dict(env), # Optional environment variables
147
+ )
148
+ ) as (read_stream, write_stream)
149
+ ):
150
+ async with ClientSession(
151
+ read_stream=read_stream, write_stream=write_stream
152
+ ) as session:
92
153
  mcp_tools_response = await session.list_tools()
93
-
94
- toolkit = MCPToolkit(name=toolkit_name, session=session, tools=mcp_tools_response.tools)
95
-
96
- remote_toolkit = RemoteToolkit(name=toolkit.name, tools=toolkit.tools, title=toolkit.title, description=toolkit.description)
154
+
155
+ toolkit = MCPToolkit(
156
+ name=toolkit_name,
157
+ session=session,
158
+ tools=mcp_tools_response.tools,
159
+ )
160
+
161
+ remote_toolkit = RemoteToolkit(
162
+ name=toolkit.name,
163
+ tools=toolkit.tools,
164
+ title=toolkit.title,
165
+ description=toolkit.description,
166
+ )
97
167
 
98
168
  await remote_toolkit.start(room=client)
99
169
  try:
@@ -101,107 +171,141 @@ async def stdio(*, project_id: str = None, room: Annotated[str, typer.Option()],
101
171
  except KeyboardInterrupt:
102
172
  await remote_toolkit.stop()
103
173
 
104
-
105
174
  except RoomException as e:
106
175
  print(f"[red]{e}[/red]")
107
176
  finally:
108
177
  await account_client.close()
109
178
 
110
- @app.async_command("http-proxy")
111
- async def stdio_host(*, command: Annotated[str, typer.Option()], host: Annotated[Optional[str], typer.Option()] = None, port: Annotated[Optional[int], typer.Option()] = None, path: Annotated[Optional[str], typer.Option()] = None, name: Annotated[Optional[str], typer.Option()] = None, env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = []):
112
179
 
180
+ @app.async_command("http-proxy")
181
+ async def stdio_host(
182
+ *,
183
+ command: Annotated[str, typer.Option()],
184
+ host: Annotated[Optional[str], typer.Option()] = None,
185
+ port: Annotated[Optional[int], typer.Option()] = None,
186
+ path: Annotated[Optional[str], typer.Option()] = None,
187
+ name: Annotated[Optional[str], typer.Option()] = None,
188
+ env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = [],
189
+ ):
113
190
  from fastmcp import FastMCP, Client
114
191
  from fastmcp.client.transports import StdioTransport
115
192
 
116
193
  parsed_command = shlex.split(command)
117
-
194
+
118
195
  # Create a client that connects to the original server
119
196
  proxy_client = Client(
120
- transport = StdioTransport(parsed_command[0], parsed_command[1:], _kv_to_dict(env)),
197
+ transport=StdioTransport(
198
+ parsed_command[0], parsed_command[1:], _kv_to_dict(env)
199
+ ),
121
200
  )
122
201
 
123
- if name == None:
202
+ if name is None:
124
203
  name = "Stdio-to-Streamable Http Proxy"
125
204
 
126
205
  # Create a proxy server that connects to the client and exposes its capabilities
127
206
  proxy = FastMCP.as_proxy(proxy_client, name=name)
128
- if path == None:
207
+ if path is None:
129
208
  path = "/mcp"
130
-
131
- await proxy.run_async(transport='streamable-http', host=host, port=port, path=path)
132
209
 
210
+ await proxy.run_async(transport="streamable-http", host=host, port=port, path=path)
133
211
 
134
- @app.async_command("sse-proxy")
135
- async def stdio_host(*, command: Annotated[str, typer.Option()], host: Annotated[Optional[str], typer.Option()] = None, port: Annotated[Optional[int], typer.Option()] = None, path: Annotated[Optional[str], typer.Option()] = None, name: Annotated[Optional[str], typer.Option()] = None, env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = []):
136
212
 
213
+ @app.async_command("sse-proxy")
214
+ async def sse_proxy(
215
+ *,
216
+ command: Annotated[str, typer.Option()],
217
+ host: Annotated[Optional[str], typer.Option()] = None,
218
+ port: Annotated[Optional[int], typer.Option()] = None,
219
+ path: Annotated[Optional[str], typer.Option()] = None,
220
+ name: Annotated[Optional[str], typer.Option()] = None,
221
+ env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = [],
222
+ ):
137
223
  from fastmcp import FastMCP, Client
138
224
  from fastmcp.client.transports import StdioTransport
139
225
 
140
226
  parsed_command = shlex.split(command)
141
-
227
+
142
228
  # Create a client that connects to the original server
143
229
  proxy_client = Client(
144
- transport = StdioTransport(parsed_command[0], parsed_command[1:], _kv_to_dict(env)),
230
+ transport=StdioTransport(
231
+ parsed_command[0], parsed_command[1:], _kv_to_dict(env)
232
+ ),
145
233
  )
146
234
 
147
- if name == None:
235
+ if name is None:
148
236
  name = "Stdio-to-SSE Proxy"
149
237
 
150
238
  # Create a proxy server that connects to the client and exposes its capabilities
151
239
  proxy = FastMCP.as_proxy(proxy_client, name=name)
152
- if path == None:
240
+ if path is None:
153
241
  path = "/sse"
154
-
155
- await proxy.run_async(transport='sse', host=host, port=port, path=path)
242
+
243
+ await proxy.run_async(transport="sse", host=host, port=port, path=path)
244
+
156
245
 
157
246
  @app.async_command("stdio-service")
158
- async def stdio_host(*, command: Annotated[str, typer.Option()], host: Annotated[Optional[str], typer.Option()] = None, port: Annotated[Optional[int], typer.Option()] = None, webhook_secret: Annotated[Optional[str], typer.Option()] = None, path: Annotated[Optional[str], typer.Option()] = None, toolkit_name: Annotated[Optional[str], typer.Option()] = None, env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = []):
247
+ async def stdio_service(
248
+ *,
249
+ command: Annotated[str, typer.Option()],
250
+ host: Annotated[Optional[str], typer.Option()] = None,
251
+ port: Annotated[Optional[int], typer.Option()] = None,
252
+ webhook_secret: Annotated[Optional[str], typer.Option()] = None,
253
+ path: Annotated[Optional[str], typer.Option()] = None,
254
+ toolkit_name: Annotated[Optional[str], typer.Option()] = None,
255
+ env: Annotated[List[str], typer.Option("--env", "-e", help="KEY=VALUE")] = [],
256
+ ):
159
257
  try:
160
-
161
258
  parsed_command = shlex.split(command)
162
-
163
- async with stdio_client(StdioServerParameters(
164
- command=parsed_command[0], # Executable
165
- args=parsed_command[1:], # Optional command line arguments
166
- env=_kv_to_dict(env), # Optional environment variables
167
- )) as (read_stream, write_stream):
168
-
169
- async with ClientSession(read_stream=read_stream, write_stream=write_stream) as session:
170
259
 
260
+ async with (
261
+ stdio_client(
262
+ StdioServerParameters(
263
+ command=parsed_command[0], # Executable
264
+ args=parsed_command[1:], # Optional command line arguments
265
+ env=_kv_to_dict(env), # Optional environment variables
266
+ )
267
+ ) as (read_stream, write_stream)
268
+ ):
269
+ async with ClientSession(
270
+ read_stream=read_stream, write_stream=write_stream
271
+ ) as session:
171
272
  mcp_tools_response = await session.list_tools()
172
-
173
- if toolkit_name == None:
273
+
274
+ if toolkit_name is None:
174
275
  toolkit_name = "mcp"
175
276
 
176
- toolkit = MCPToolkit(name=toolkit_name, session=session, tools=mcp_tools_response.tools)
177
-
178
- if port == None:
277
+ toolkit = MCPToolkit(
278
+ name=toolkit_name, session=session, tools=mcp_tools_response.tools
279
+ )
179
280
 
281
+ if port is None:
180
282
  port = int(os.getenv("MESHAGENT_PORT", "8080"))
181
283
 
182
- if host == None:
183
-
284
+ if host is None:
184
285
  host = "0.0.0.0"
185
286
 
186
287
  service_host = ServiceHost(
187
- host=host,
188
- port=port,
189
- webhook_secret=webhook_secret
288
+ host=host, port=port, webhook_secret=webhook_secret
190
289
  )
191
290
 
192
- if path == None:
291
+ if path is None:
193
292
  path = "/service"
194
293
 
195
- print(f"[bold green]Starting service host on {host}:{port}{path}...[/bold green]")
294
+ print(
295
+ f"[bold green]Starting service host on {host}:{port}{path}...[/bold green]"
296
+ )
297
+
196
298
  @service_host.path(path=path)
197
299
  class CustomToolkit(RemoteToolkit):
198
300
  def __init__(self):
199
- super().__init__(name=toolkit.name, tools=toolkit.tools, title=toolkit.title, description=toolkit.description)
301
+ super().__init__(
302
+ name=toolkit.name,
303
+ tools=toolkit.tools,
304
+ title=toolkit.title,
305
+ description=toolkit.description,
306
+ )
200
307
 
201
-
202
308
  await service_host.run()
203
309
 
204
-
205
310
  except RoomException as e:
206
311
  print(f"[red]{e}[/red]")
207
-
@@ -7,7 +7,11 @@ from typing import Annotated, Dict, Optional
7
7
 
8
8
  from meshagent.cli import async_typer
9
9
  from meshagent.cli.helper import get_client, print_json_table, resolve_project_id
10
- from meshagent.api.accounts_client import PullSecret, KeysSecret, SecretLike # or wherever you defined them
10
+ from meshagent.api.accounts_client import (
11
+ PullSecret,
12
+ KeysSecret,
13
+ SecretLike,
14
+ ) # or wherever you defined them
11
15
 
12
16
  # --------------------------------------------------------------------------
13
17
  # App Definition
@@ -19,6 +23,7 @@ secrets_app = async_typer.AsyncTyper(help="Manage secrets for your project.")
19
23
  # Utility helpers
20
24
  # --------------------------------------------------------------------------
21
25
 
26
+
22
27
  def _parse_kv_inline(source: str | None) -> Dict[str, str]:
23
28
  """
24
29
  Parse a space-separated list of `key=value` tokens into a dict.
@@ -39,7 +44,10 @@ def _parse_kv_inline(source: str | None) -> Dict[str, str]:
39
44
  # Subcommand group: "keys"
40
45
  # e.g.: meshagent secrets keys create --name <NAME> --data ...
41
46
  # --------------------------------------------------------------------------
42
- keys_app = async_typer.AsyncTyper(help="Create or update environment-based key-value secrets.")
47
+ keys_app = async_typer.AsyncTyper(
48
+ help="Create or update environment-based key-value secrets."
49
+ )
50
+
43
51
 
44
52
  @keys_app.async_command("create")
45
53
  async def create_keys_secret(
@@ -52,7 +60,7 @@ async def create_keys_secret(
52
60
  "--data",
53
61
  help="Format: key=value key2=value (space-separated)",
54
62
  ),
55
- ]
63
+ ],
56
64
  ):
57
65
  """
58
66
  Create a new 'keys' secret (opaque env-vars).
@@ -86,7 +94,7 @@ async def update_keys_secret(
86
94
  "--data",
87
95
  help="Format: key=value key2=value (space-separated)",
88
96
  ),
89
- ]
97
+ ],
90
98
  ):
91
99
  """
92
100
  Update an existing 'keys' secret (opaque env-vars).
@@ -111,20 +119,27 @@ async def update_keys_secret(
111
119
  # Subcommand group: "docker"
112
120
  # e.g.: meshagent secrets docker create --name myregistry --server ...
113
121
  # --------------------------------------------------------------------------
114
- docker_app = async_typer.AsyncTyper(help="Create or update a Docker registry pull secret.")
122
+ docker_app = async_typer.AsyncTyper(
123
+ help="Create or update a Docker registry pull secret."
124
+ )
125
+
115
126
 
116
127
  @docker_app.async_command("create")
117
128
  async def create_docker_secret(
118
129
  *,
119
130
  project_id: Optional[str] = typer.Option(None),
120
131
  name: Annotated[str, typer.Option(help="Secret name")],
121
- server: Annotated[str, typer.Option(help="Docker registry server, e.g. index.docker.io")],
132
+ server: Annotated[
133
+ str, typer.Option(help="Docker registry server, e.g. index.docker.io")
134
+ ],
122
135
  username: Annotated[str, typer.Option(help="Registry user name")],
123
136
  password: Annotated[str, typer.Option(help="Registry password")],
124
137
  email: Annotated[
125
138
  str,
126
- typer.Option("--email", help="User email for Docker config", show_default=False)
127
- ] = "none@example.com"
139
+ typer.Option(
140
+ "--email", help="User email for Docker config", show_default=False
141
+ ),
142
+ ] = "none@example.com",
128
143
  ):
129
144
  """
130
145
  Create a new Docker pull secret (generic).
@@ -158,8 +173,10 @@ async def update_docker_secret(
158
173
  password: Annotated[str, typer.Option(help="Registry password")],
159
174
  email: Annotated[
160
175
  str,
161
- typer.Option("--email", help="User email for Docker config", show_default=False)
162
- ] = "none@example.com"
176
+ typer.Option(
177
+ "--email", help="User email for Docker config", show_default=False
178
+ ),
179
+ ] = "none@example.com",
163
180
  ):
164
181
  """
165
182
  Update an existing Docker pull secret (generic).
@@ -185,7 +202,10 @@ async def update_docker_secret(
185
202
  # Subcommand group: "acr"
186
203
  # e.g.: meshagent secrets acr create --name <NAME> --server <REG>.azurecr.io ...
187
204
  # --------------------------------------------------------------------------
188
- acr_app = async_typer.AsyncTyper(help="Create or update an Azure Container Registry pull secret.")
205
+ acr_app = async_typer.AsyncTyper(
206
+ help="Create or update an Azure Container Registry pull secret."
207
+ )
208
+
189
209
 
190
210
  @acr_app.async_command("create")
191
211
  async def create_acr_secret(
@@ -194,7 +214,7 @@ async def create_acr_secret(
194
214
  name: Annotated[str, typer.Option(help="Secret name")],
195
215
  server: Annotated[str, typer.Option(help="ACR server, e.g. myregistry.azurecr.io")],
196
216
  username: Annotated[str, typer.Option(help="Service principal ID")],
197
- password: Annotated[str, typer.Option(help="Service principal secret/password")]
217
+ password: Annotated[str, typer.Option(help="Service principal secret/password")],
198
218
  ):
199
219
  """
200
220
  Create a new ACR pull secret (defaults email to 'none@microsoft.com').
@@ -209,13 +229,14 @@ async def create_acr_secret(
209
229
  server=server,
210
230
  username=username,
211
231
  password=password,
212
- email="none@microsoft.com", # Set a default for ACR usage
232
+ email="none@microsoft.com", # Set a default for ACR usage
213
233
  )
214
234
  secret_id = await client.create_secret(project_id=project_id, secret=secret_obj)
215
235
  print(f"[green]Created ACR pull secret:[/] {secret_id}")
216
236
  finally:
217
237
  await client.close()
218
238
 
239
+
219
240
  @acr_app.async_command("update")
220
241
  async def update_acr_secret(
221
242
  *,
@@ -224,7 +245,7 @@ async def update_acr_secret(
224
245
  name: Annotated[str, typer.Option(help="Secret name")],
225
246
  server: Annotated[str, typer.Option(help="ACR server, e.g. myregistry.azurecr.io")],
226
247
  username: Annotated[str, typer.Option(help="Service principal ID")],
227
- password: Annotated[str, typer.Option(help="Service principal secret/password")]
248
+ password: Annotated[str, typer.Option(help="Service principal secret/password")],
228
249
  ):
229
250
  """
230
251
  Update an existing ACR pull secret (defaults email to 'none@microsoft.com').
@@ -251,7 +272,10 @@ async def update_acr_secret(
251
272
  # e.g.: meshagent secrets gar create --name <NAME> --server ...
252
273
  # (Typically sets email='none@google.com' and username='_json_key')
253
274
  # --------------------------------------------------------------------------
254
- gar_app = async_typer.AsyncTyper(help="Create or update a Google Artifact Registry pull secret.")
275
+ gar_app = async_typer.AsyncTyper(
276
+ help="Create or update a Google Artifact Registry pull secret."
277
+ )
278
+
255
279
 
256
280
  @gar_app.async_command("create")
257
281
  async def create_gar_secret(
@@ -259,11 +283,13 @@ async def create_gar_secret(
259
283
  project_id: Optional[str] = typer.Option(None),
260
284
  name: Annotated[str, typer.Option(help="Secret name")],
261
285
  server: Annotated[str, typer.Option(help="GAR host, e.g. us-west1-docker.pkg.dev")],
262
- json_key: Annotated[str, typer.Option(help="Entire GCP service account JSON as string")]
286
+ json_key: Annotated[
287
+ str, typer.Option(help="Entire GCP service account JSON as string")
288
+ ],
263
289
  ):
264
290
  """
265
291
  Create a new Google Artifact Registry pull secret.
266
-
292
+
267
293
  By default, sets email='none@google.com', username='_json_key'
268
294
  """
269
295
  client = await get_client()
@@ -283,6 +309,7 @@ async def create_gar_secret(
283
309
  finally:
284
310
  await client.close()
285
311
 
312
+
286
313
  @gar_app.async_command("update")
287
314
  async def update_gar_secret(
288
315
  *,
@@ -290,7 +317,9 @@ async def update_gar_secret(
290
317
  secret_id: Annotated[str, typer.Option(help="Existing secret ID")],
291
318
  name: Annotated[str, typer.Option(help="Secret name")],
292
319
  server: Annotated[str, typer.Option(help="GAR host, e.g. us-west1-docker.pkg.dev")],
293
- json_key: Annotated[str, typer.Option(help="Entire GCP service account JSON as string")]
320
+ json_key: Annotated[
321
+ str, typer.Option(help="Entire GCP service account JSON as string")
322
+ ],
294
323
  ):
295
324
  """
296
325
  Update an existing Google Artifact Registry pull secret.
@@ -316,6 +345,7 @@ async def update_gar_secret(
316
345
  # Additional commands (shared by all secrets): list, delete
317
346
  # --------------------------------------------------------------------------
318
347
 
348
+
319
349
  @secrets_app.async_command("list")
320
350
  async def secret_list(*, project_id: Optional[str] = None):
321
351
  """List all secrets in the project (typed as Docker/ACR/GAR or Keys secrets)."""
@@ -329,7 +359,7 @@ async def secret_list(*, project_id: Optional[str] = None):
329
359
  rows = []
330
360
  for s in secrets:
331
361
  row = {
332
- "id": s.id,
362
+ "id": s.id,
333
363
  "name": s.name,
334
364
  "type": s.type,
335
365
  }
@@ -353,7 +383,7 @@ async def secret_list(*, project_id: Optional[str] = None):
353
383
  async def secret_delete(
354
384
  *,
355
385
  project_id: Optional[str] = None,
356
- secret_id: Annotated[str, typer.Argument(help="ID of the secret to delete")]
386
+ secret_id: Annotated[str, typer.Argument(help="ID of the secret to delete")],
357
387
  ):
358
388
  """Delete a secret."""
359
389
  client = await get_client()
@@ -10,33 +10,43 @@ from meshagent.api.helpers import meshagent_base_url, websocket_room_url
10
10
 
11
11
  app = async_typer.AsyncTyper()
12
12
 
13
+
13
14
  @app.async_command("watch")
14
15
  async def watch_logs(
15
16
  *,
16
- project_id: Annotated[Optional[str], typer.Option(..., help="Project ID (if not set, will try to use the active project)")] = None,
17
+ project_id: Annotated[
18
+ Optional[str],
19
+ typer.Option(
20
+ ..., help="Project ID (if not set, will try to use the active project)"
21
+ ),
22
+ ] = None,
17
23
  room: Annotated[str, typer.Option(..., help="Name of the room to connect to")],
18
24
  api_key_id: Annotated[Optional[str], typer.Option(..., help="API Key ID")] = None,
19
25
  name: Annotated[str, typer.Option(..., help="Participant name")] = "cli",
20
- role: Annotated[str, typer.Option(..., help="Role to assign to this participant")] = "user"
26
+ role: Annotated[
27
+ str, typer.Option(..., help="Role to assign to this participant")
28
+ ] = "user",
21
29
  ):
22
30
  """
23
31
  Watch logs from the developer feed in the specified room.
24
32
  """
25
-
33
+
26
34
  account_client = await get_client()
27
35
  try:
28
36
  # Resolve project ID (or fetch from the active project if not provided)
29
37
  project_id = await resolve_project_id(project_id=project_id)
30
38
  api_key_id = await resolve_api_key(project_id, api_key_id)
31
-
39
+
32
40
  # Decrypt the project's API key
33
- key = (await account_client.decrypt_project_api_key(project_id=project_id, id=api_key_id))["token"]
41
+ key = (
42
+ await account_client.decrypt_project_api_key(
43
+ project_id=project_id, id=api_key_id
44
+ )
45
+ )["token"]
34
46
 
35
47
  # Build a participant token
36
48
  token = ParticipantToken(
37
- name=name,
38
- project_id=project_id,
39
- api_key_id=api_key_id
49
+ name=name, project_id=project_id, api_key_id=api_key_id
40
50
  )
41
51
  token.add_role_grant(role=role)
42
52
  token.add_room_grant(room)
@@ -45,7 +55,7 @@ async def watch_logs(
45
55
  async with RoomClient(
46
56
  protocol=WebSocketClientProtocol(
47
57
  url=websocket_room_url(room_name=room, base_url=meshagent_base_url()),
48
- token=token.to_jwt(token=key)
58
+ token=token.to_jwt(token=key),
49
59
  )
50
60
  ) as client:
51
61
  # Create a developer client from the room client