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.
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/PKG-INFO +1 -1
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/pyproject.toml +1 -1
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/agent_bridge.py +1 -1
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/api_client.py +20 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/config.py +6 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/main.py +33 -15
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/.gitignore +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/LICENSE +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/README.md +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/__init__.py +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/__main__.py +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/src/swiftgate_cli/sse_listener.py +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/tests/test_agent_bridge.py +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/tests/test_config.py +0 -0
- {swiftgate_cli-1.0.3 → swiftgate_cli-1.0.5}/tests/test_sse_listener.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swiftgate-cli
|
|
3
|
-
Version: 1.0.
|
|
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
|
|
@@ -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"\
|
|
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.
|
|
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
|
|
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
|
-
|
|
88
|
-
|
|
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(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|