swiftgate-cli 1.0.3__tar.gz → 1.0.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: swiftgate-cli
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: SwiftGate CLI — autonomous bidirectional agent bridge for SwiftGate OS
5
5
  Project-URL: Homepage, https://swiftgate.ai
6
6
  Project-URL: Repository, https://github.com/thetaroot/swiftgate
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "swiftgate-cli"
7
- version = "1.0.3"
7
+ version = "1.0.5"
8
8
  description = "SwiftGate CLI — autonomous bidirectional agent bridge for SwiftGate OS"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -146,7 +146,7 @@ class AgentBridge:
146
146
  if not self._running or self._master_fd is None:
147
147
  return
148
148
 
149
- msg = f"\n# SwiftGate: {count} pending tasks. Run swiftgate_agent_get_task\n"
149
+ msg = f"\r\nSwiftGate: You have {count} pending tasks. Call swiftgate_agent_get_task\r\n"
150
150
  try:
151
151
  os.write(self._master_fd, msg.encode("utf-8"))
152
152
  logger.debug("Wake injected for %s (%d pending)", self._slug, count)
@@ -74,6 +74,26 @@ class APIClient:
74
74
  except Exception:
75
75
  return False
76
76
 
77
+ async def fetch_agent_token(self, workspace_slug: str) -> dict | None:
78
+ """Fetch MCP token + agent config from SwiftGate.
79
+
80
+ Authenticated via account token. Returns dict with
81
+ mcp_token, agent_type, server_url or None on failure.
82
+ """
83
+ url = self._cli_url("start-agent")
84
+ try:
85
+ async with aiohttp.ClientSession() as session:
86
+ async with session.post(
87
+ url, json={"workspace_slug": workspace_slug},
88
+ headers=self._headers(),
89
+ timeout=aiohttp.ClientTimeout(total=10),
90
+ ) as resp:
91
+ if resp.status != 200:
92
+ return None
93
+ return await resp.json()
94
+ except Exception:
95
+ return None
96
+
77
97
  def get_sse_url(self) -> str:
78
98
  """URL for the CLI SSE wake stream."""
79
99
  return self._cli_url("listen")
@@ -33,6 +33,12 @@ def _ensure_config_dir() -> None:
33
33
  pass
34
34
 
35
35
 
36
+ def ensure_config_dir() -> Path:
37
+ """Ensure ~/.swiftgate/ exists and return its path."""
38
+ _ensure_config_dir()
39
+ return _CONFIG_DIR
40
+
41
+
36
42
  def _set_permissions(path: Path) -> None:
37
43
  """Set file permissions to 0600 (owner read/write only)."""
38
44
  try:
@@ -18,6 +18,7 @@ from typing import Optional
18
18
  import click
19
19
 
20
20
  from swiftgate_cli.config import (
21
+ ensure_config_dir,
21
22
  is_setup, set_setup, get_server, list_agents as cfg_list_agents,
22
23
  add_agent as cfg_add_agent, remove_agent as cfg_remove_agent,
23
24
  get_agent as cfg_get_agent,
@@ -26,16 +27,19 @@ from swiftgate_cli.api_client import APIClient
26
27
  from swiftgate_cli.sse_listener import SSEWakeListener
27
28
  from swiftgate_cli.agent_bridge import AgentBridge
28
29
 
30
+ _log_dir = ensure_config_dir()
29
31
  logging.basicConfig(
30
32
  level=logging.INFO,
31
33
  format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
32
34
  datefmt="%H:%M:%S",
35
+ filename=str(_log_dir / "swiftgate-cli.log"),
36
+ filemode="a",
33
37
  )
34
38
  logger = logging.getLogger("swiftgate")
35
39
 
36
40
 
37
41
  @click.group()
38
- @click.version_option(version="1.0.3", prog_name="swiftgate-cli")
42
+ @click.version_option(version="1.0.5", prog_name="swiftgate-cli")
39
43
  def cli():
40
44
  """swiftgate-cli — Autonomous bidirectional agent bridge for SwiftGate OS.
41
45
 
@@ -80,16 +84,12 @@ def setup(token: str, server: str):
80
84
 
81
85
  @cli.command()
82
86
  @click.option("--agent", required=True, help="Agent workspace slug")
83
- @click.option("--mcp-token", default="", help="MCP token from agent registration (sg_ea_...)")
87
+ @click.option("--mcp-token", default="", help="MCP token (optional auto-fetched if not provided)")
84
88
  def start(agent: str, mcp_token: str):
85
89
  """Start an agent and bridge it to SwiftGate.
86
90
 
87
- Fetches agent config from SwiftGate, writes MCP configuration,
88
- spawns the agent process, and starts the SSE wake listener.
89
- stdin/stdout is forwarded transparently.
90
-
91
- The MCP token is required on first start. It is stored in
92
- ~/.swiftgate/config.json for subsequent starts.
91
+ MCP token is auto-fetched from SwiftGate using the account token.
92
+ No copy-paste needed just run: swiftgate-cli start --agent my-agent
93
93
  """
94
94
  asyncio.run(_start_async(agent, mcp_token))
95
95
 
@@ -99,18 +99,28 @@ async def _start_async(agent: str, mcp_token: str) -> None:
99
99
  click.echo(click.style("Not set up. Run: swiftgate-cli setup --token sg_acc_...", fg="red"))
100
100
  sys.exit(1)
101
101
 
102
+ client = APIClient()
103
+
102
104
  token = mcp_token or _get_stored_token(agent)
105
+ agent_type = _get_stored_type(agent) or "opencode"
106
+
103
107
  if not token:
104
- click.echo(click.style(
105
- "MCP token required. Copy the full command from the agent creation screen.",
106
- fg="yellow"))
107
- click.echo(f"Usage: swiftgate-cli start --agent {agent} --mcp-token sg_ea_...")
108
- sys.exit(1)
108
+ click.echo("Fetching agent config from SwiftGate...")
109
+ config = await client.fetch_agent_token(agent)
110
+ if config and config.get("mcp_token"):
111
+ token = config["mcp_token"]
112
+ agent_type = config.get("agent_type") or agent_type
113
+ _store_token(agent, token)
114
+ _store_type(agent, agent_type)
115
+ else:
116
+ click.echo(click.style(
117
+ "Could not fetch agent config. Provide MCP token manually:",
118
+ fg="yellow"))
119
+ click.echo(f"Usage: swiftgate-cli start --agent {agent} --mcp-token sg_ea_...")
120
+ sys.exit(1)
109
121
 
110
122
  if mcp_token and mcp_token.startswith("sg_ea_"):
111
123
  _store_token(agent, mcp_token)
112
-
113
- agent_type = _get_stored_type(agent) or "opencode"
114
124
  command = _agent_command(agent_type)
115
125
  if not command:
116
126
  click.echo(click.style(f"Unknown agent type: {agent_type}", fg="red"))
@@ -220,6 +230,14 @@ def _store_token(slug: str, token: str) -> None:
220
230
  save(cfg)
221
231
 
222
232
 
233
+ def _store_type(slug: str, agent_type: str) -> None:
234
+ """Save agent type to local config."""
235
+ from swiftgate_cli.config import load, save
236
+ cfg = load()
237
+ cfg.setdefault("agents", {}).setdefault(slug, {})["type"] = agent_type
238
+ save(cfg)
239
+
240
+
223
241
  def _get_stored_type(slug: str) -> str:
224
242
  """Get saved agent type from local config."""
225
243
  from swiftgate_cli.config import load
File without changes
File without changes
File without changes